1
0
Fork 0

Reduce # of memcpy from storage engine layer (#8685)

This commit is contained in:
Simon 2019-04-08 22:43:29 +02:00 committed by Jan
parent 4f7923a971
commit 2b594bdab5
41 changed files with 651 additions and 725 deletions

View File

@ -55,5 +55,6 @@ extern __thread IOStatsContext iostats_context;
#define IOSTATS(metric) 0 #define IOSTATS(metric) 0
#define IOSTATS_TIMER_GUARD(metric) #define IOSTATS_TIMER_GUARD(metric)
#define IOSTATS_CPU_TIMER_GUARD(metric, env)
#endif // ROCKSDB_SUPPORT_THREAD_LOCAL #endif // ROCKSDB_SUPPORT_THREAD_LOCAL

View File

@ -452,33 +452,29 @@ bool ClusterCollection::readDocumentWithCallback(transaction::Methods* trx,
Result ClusterCollection::insert(arangodb::transaction::Methods*, Result ClusterCollection::insert(arangodb::transaction::Methods*,
arangodb::velocypack::Slice const, arangodb::velocypack::Slice const,
arangodb::ManagedDocumentResult&, arangodb::ManagedDocumentResult&,
OperationOptions&, TRI_voc_tick_t&, bool, OperationOptions&, bool /*lock*/,
TRI_voc_tick_t&, KeyLockInfo* /*keyLock*/, KeyLockInfo* /*keyLock*/,
std::function<Result(void)> const&) { std::function<void()> const&) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
} }
Result ClusterCollection::update(arangodb::transaction::Methods* trx, Result ClusterCollection::update(arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
ManagedDocumentResult& mdr, OperationOptions& options, ManagedDocumentResult& mdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool, bool /*lock*/, ManagedDocumentResult& previous) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
} }
Result ClusterCollection::replace(transaction::Methods* trx, Result ClusterCollection::replace(transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
ManagedDocumentResult& mdr, OperationOptions& options, ManagedDocumentResult& mdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool, bool /*lock*/, ManagedDocumentResult& previous) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
} }
Result ClusterCollection::remove(transaction::Methods& trx, velocypack::Slice slice, Result ClusterCollection::remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previous, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool /*lock*/, KeyLockInfo* /*keyLock*/, std::function<void()> const& /*callbackDuringLock*/
TRI_voc_rid_t& prevRev, TRI_voc_rid_t& revisionId,
KeyLockInfo* /*keyLock*/, std::function<Result(void)> const& /*callbackDuringLock*/
) { ) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
} }

View File

@ -144,25 +144,21 @@ class ClusterCollection final : public PhysicalCollection {
Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
arangodb::ManagedDocumentResult& result, OperationOptions& options, arangodb::ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, KeyLockInfo* /*keyLockInfo*/,
TRI_voc_tick_t& revisionId, KeyLockInfo* /*keyLockInfo*/, std::function<void()> const& callbackDuringLock) override;
std::function<Result(void)> const& callbackDuringLock) override;
Result update(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice, Result update(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, ManagedDocumentResult& previous) override;
ManagedDocumentResult& previous) override;
Result replace(transaction::Methods* trx, arangodb::velocypack::Slice const newSlice, Result replace(transaction::Methods* trx, arangodb::velocypack::Slice const newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previous) override;
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) override;
Result remove(transaction::Methods& trx, velocypack::Slice slice, Result remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previous, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_rid_t& revisionId, KeyLockInfo* keyLockInfo, std::function<void()> const& callbackDuringLock) override;
std::function<Result(void)> const& callbackDuringLock) override;
protected: protected:
/// @brief Inject figures that are specific to StorageEngine /// @brief Inject figures that are specific to StorageEngine

View File

@ -2014,9 +2014,9 @@ Result MMFilesCollection::read(transaction::Methods* trx, VPackSlice const& key,
} }
TRI_DEFER(if (lock) { unlockRead(useDeadlockDetector, trx->state()); }); TRI_DEFER(if (lock) { unlockRead(useDeadlockDetector, trx->state()); });
Result res = lookupDocument(trx, key, result); LocalDocumentId const documentId = lookupDocument(trx, key, result);
if (res.fail()) { if (documentId.empty()) {
return res; return Result(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
} }
// we found a document // we found a document
@ -2037,7 +2037,7 @@ bool MMFilesCollection::readDocument(transaction::Methods* trx,
ManagedDocumentResult& result) const { ManagedDocumentResult& result) const {
uint8_t const* vpack = lookupDocumentVPack(documentId); uint8_t const* vpack = lookupDocumentVPack(documentId);
if (vpack != nullptr) { if (vpack != nullptr) {
result.setUnmanaged(vpack, documentId); result.setUnmanaged(vpack);
return true; return true;
} }
return false; return false;
@ -2076,7 +2076,7 @@ bool MMFilesCollection::readDocumentConditional(transaction::Methods* trx,
TRI_ASSERT(documentId.isSet()); TRI_ASSERT(documentId.isSet());
uint8_t const* vpack = lookupDocumentVPackConditional(documentId, maxTick, true); uint8_t const* vpack = lookupDocumentVPackConditional(documentId, maxTick, true);
if (vpack != nullptr) { if (vpack != nullptr) {
result.setUnmanaged(vpack, documentId); result.setUnmanaged(vpack);
return true; return true;
} }
return false; return false;
@ -2831,17 +2831,17 @@ LocalDocumentId MMFilesCollection::reuseOrCreateLocalDocumentId(OperationOptions
} }
Result MMFilesCollection::insert(arangodb::transaction::Methods* trx, VPackSlice const slice, Result MMFilesCollection::insert(arangodb::transaction::Methods* trx, VPackSlice const slice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& resultMdr,
OperationOptions& options, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_tick_t& revisionId, KeyLockInfo* keyLockInfo, std::function<void()> const& callbackDuringLock) {
std::function<Result(void)> const& callbackDuringLock) {
LocalDocumentId const documentId = reuseOrCreateLocalDocumentId(options); LocalDocumentId const documentId = reuseOrCreateLocalDocumentId(options);
auto isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type()); auto isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type());
transaction::BuilderLeaser builder(trx); transaction::BuilderLeaser builder(trx);
VPackSlice newSlice; VPackSlice newSlice;
Result res(TRI_ERROR_NO_ERROR); Result res(TRI_ERROR_NO_ERROR);
TRI_voc_rid_t revisionId = 0;
if (options.recoveryData == nullptr) { if (options.recoveryData == nullptr) {
res = newObjectForInsert(trx, slice, isEdgeCollection, *builder.get(), res = newObjectForInsert(trx, slice, isEdgeCollection, *builder.get(),
options.isRestore, revisionId); options.isRestore, revisionId);
@ -2871,11 +2871,12 @@ Result MMFilesCollection::insert(arangodb::transaction::Methods* trx, VPackSlice
if (revSlice.isString()) { if (revSlice.isString()) {
VPackValueLength l; VPackValueLength l;
char const* p = revSlice.getString(l); char const* p = revSlice.getStringUnchecked(l);
TRI_ASSERT(p != nullptr); TRI_ASSERT(p != nullptr);
revisionId = TRI_StringToRid(p, l, false); revisionId = TRI_StringToRid(p, l, false);
} }
} }
TRI_ASSERT(revisionId != 0);
// create marker // create marker
MMFilesCrudMarker insertMarker( MMFilesCrudMarker insertMarker(
@ -2957,7 +2958,7 @@ Result MMFilesCollection::insert(arangodb::transaction::Methods* trx, VPackSlice
} }
if (res.ok() && callbackDuringLock != nullptr) { if (res.ok() && callbackDuringLock != nullptr) {
res = callbackDuringLock(); callbackDuringLock();
} }
} catch (...) { } catch (...) {
// the collectionLocker may have thrown in its constructor... // the collectionLocker may have thrown in its constructor...
@ -2976,9 +2977,18 @@ Result MMFilesCollection::insert(arangodb::transaction::Methods* trx, VPackSlice
} }
if (res.ok()) { if (res.ok()) {
result.setManaged(doc.begin(), documentId); if (options.returnNew) {
// store the tick that was used for writing the document resultMdr.setManaged(doc.begin());
resultMarkerTick = operation.tick(); TRI_ASSERT(resultMdr.revisionId() == revisionId);
} else if (!options.silent) { // need to pass up revision and key
transaction::BuilderLeaser keyBuilder(trx);
keyBuilder->openObject(/*unindexed*/true);
keyBuilder->add(StaticStrings::KeyString, transaction::helpers::extractKeyFromDocument(doc));
keyBuilder->close();
resultMdr.setManaged()->assign(reinterpret_cast<char const*>(keyBuilder->start()),
keyBuilder->size());
resultMdr.setRevisionId(revisionId);
}
} }
return res; return res;
@ -3375,13 +3385,14 @@ Result MMFilesCollection::insertDocument(arangodb::transaction::Methods& trx,
} }
Result MMFilesCollection::update(arangodb::transaction::Methods* trx, Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
VPackSlice const newSlice, ManagedDocumentResult& result, VPackSlice const newSlice, ManagedDocumentResult& resultMdr,
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, OperationOptions& options,
bool lock, TRI_voc_rid_t& prevRev, bool lock, ManagedDocumentResult& previousMdr) {
ManagedDocumentResult& previous) {
VPackSlice key = newSlice.get(StaticStrings::KeyString); VPackSlice key = newSlice.get(StaticStrings::KeyString);
if (key.isNone()) { if (key.isNone()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); return Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
} else if (!key.isString()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
} }
LocalDocumentId const documentId = reuseOrCreateLocalDocumentId(options); LocalDocumentId const documentId = reuseOrCreateLocalDocumentId(options);
@ -3396,16 +3407,13 @@ Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
trx->state(), lock); trx->state(), lock);
// get the previous revision // get the previous revision
Result res = lookupDocument(trx, key, previous); LocalDocumentId const oldDocumentId = lookupDocument(trx, key, previousMdr);
if (oldDocumentId.empty()) {
if (res.fail()) { return Result(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
return res;
} }
LocalDocumentId const oldDocumentId = previous.localDocumentId(); VPackSlice const oldDoc(previousMdr.vpack());
VPackSlice const oldDoc(previous.vpack()); TRI_ASSERT(previousMdr.revisionId() != 0);
TRI_voc_rid_t const oldRevisionId = transaction::helpers::extractRevFromDocument(oldDoc);
prevRev = oldRevisionId;
TRI_IF_FAILURE("UpdateDocumentNoMarker") { TRI_IF_FAILURE("UpdateDocumentNoMarker") {
// test what happens when no marker can be created // test what happens when no marker can be created
@ -3423,7 +3431,7 @@ Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
if (newSlice.isObject()) { if (newSlice.isObject()) {
expectedRev = TRI_ExtractRevisionId(newSlice); expectedRev = TRI_ExtractRevisionId(newSlice);
} }
int res = checkRevision(trx, expectedRev, prevRev); int res = checkRevision(trx, expectedRev, previousMdr.revisionId());
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
return Result(res); return Result(res);
} }
@ -3431,7 +3439,7 @@ Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
if (newSlice.length() <= 1) { if (newSlice.length() <= 1) {
// no need to do anything // no need to do anything
result = previous; resultMdr = previousMdr;
if (_logicalCollection.waitForSync()) { if (_logicalCollection.waitForSync()) {
options.waitForSync = true; options.waitForSync = true;
@ -3440,6 +3448,7 @@ Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
return Result(); return Result();
} }
Result res;
// merge old and new values // merge old and new values
TRI_voc_rid_t revisionId; TRI_voc_rid_t revisionId;
transaction::BuilderLeaser builder(trx); transaction::BuilderLeaser builder(trx);
@ -3503,11 +3512,10 @@ Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
if (res.fail()) { if (res.fail()) {
operation.revert(trx); operation.revert(trx);
} else { } else {
result.setManaged(newDoc.begin(), documentId); if (options.returnNew) {
resultMdr.setManaged(newDoc.begin());
if (options.waitForSync) { } else { // need to pass revId manually
// store the tick that was used for writing the new document resultMdr.setRevisionId(revisionId);
resultMarkerTick = operation.tick();
} }
} }
@ -3515,9 +3523,8 @@ Result MMFilesCollection::update(arangodb::transaction::Methods* trx,
} }
Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const newSlice, Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previousMdr) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
LocalDocumentId const documentId = reuseOrCreateLocalDocumentId(options); LocalDocumentId const documentId = reuseOrCreateLocalDocumentId(options);
auto isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type()); auto isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type());
@ -3527,6 +3534,8 @@ Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const ne
VPackSlice key = newSlice.get(StaticStrings::KeyString); VPackSlice key = newSlice.get(StaticStrings::KeyString);
if (key.isNone()) { if (key.isNone()) {
return TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD; return TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
} else if (!key.isString()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
} }
bool const useDeadlockDetector = bool const useDeadlockDetector =
@ -3536,10 +3545,9 @@ Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const ne
trx->state(), lock); trx->state(), lock);
// get the previous revision // get the previous revision
Result res = lookupDocument(trx, key, previous); LocalDocumentId const oldDocumentId = lookupDocument(trx, key, previousMdr);
if (oldDocumentId.empty()) {
if (res.fail()) { return Result(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
return res;
} }
TRI_IF_FAILURE("ReplaceDocumentNoMarker") { TRI_IF_FAILURE("ReplaceDocumentNoMarker") {
@ -3552,12 +3560,10 @@ Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const ne
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
} }
uint8_t const* vpack = previous.vpack(); uint8_t const* vpack = previousMdr.vpack();
LocalDocumentId const oldDocumentId = previous.localDocumentId(); TRI_ASSERT(previousMdr.revisionId() != 0);
VPackSlice oldDoc(vpack); VPackSlice const oldDoc(vpack);
TRI_voc_rid_t oldRevisionId = transaction::helpers::extractRevFromDocument(oldDoc);
prevRev = oldRevisionId;
// Check old revision: // Check old revision:
if (!options.ignoreRevs) { if (!options.ignoreRevs) {
@ -3565,12 +3571,13 @@ Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const ne
if (newSlice.isObject()) { if (newSlice.isObject()) {
expectedRev = TRI_ExtractRevisionId(newSlice); expectedRev = TRI_ExtractRevisionId(newSlice);
} }
int res = checkRevision(trx, expectedRev, prevRev); int res = checkRevision(trx, expectedRev, previousMdr.revisionId());
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
return Result(res); return Result(res);
} }
} }
Result res;
// merge old and new values // merge old and new values
TRI_voc_rid_t revisionId; TRI_voc_rid_t revisionId;
transaction::BuilderLeaser builder(trx); transaction::BuilderLeaser builder(trx);
@ -3630,11 +3637,10 @@ Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const ne
if (res.fail()) { if (res.fail()) {
operation.revert(trx); operation.revert(trx);
} else { } else {
result.setManaged(newDoc.begin(), documentId); if (options.returnNew) {
resultMdr.setManaged(newDoc.begin());
if (options.waitForSync) { } else { // need to pass revId manually
// store the tick that was used for writing the new document resultMdr.setRevisionId(revisionId);
resultMarkerTick = operation.tick();
} }
} }
@ -3642,16 +3648,13 @@ Result MMFilesCollection::replace(transaction::Methods* trx, VPackSlice const ne
} }
Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice slice, Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previousMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_rid_t& prevRev, TRI_voc_rid_t& revisionId, std::function<void()> const& callbackDuringLock) {
KeyLockInfo* keyLockInfo,
std::function<Result(void)> const& callbackDuringLock) {
prevRev = 0;
LocalDocumentId const documentId = LocalDocumentId::create(); LocalDocumentId const documentId = LocalDocumentId::create();
transaction::BuilderLeaser builder(&trx); transaction::BuilderLeaser builder(&trx);
TRI_voc_rid_t revisionId;
newObjectForRemove(&trx, slice, *builder.get(), options.isRestore, revisionId); newObjectForRemove(&trx, slice, *builder.get(), options.isRestore, revisionId);
TRI_IF_FAILURE("RemoveDocumentNoMarker") { TRI_IF_FAILURE("RemoveDocumentNoMarker") {
@ -3683,7 +3686,6 @@ Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice sl
} }
VPackSlice key; VPackSlice key;
if (slice.isString()) { if (slice.isString()) {
key = slice; key = slice;
} else { } else {
@ -3691,6 +3693,9 @@ Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice sl
} }
TRI_ASSERT(!key.isNone()); TRI_ASSERT(!key.isNone());
if (!key.isString()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
}
TRI_ASSERT(keyLockInfo != nullptr); TRI_ASSERT(keyLockInfo != nullptr);
if (keyLockInfo->shouldLock) { if (keyLockInfo->shouldLock) {
@ -3705,23 +3710,20 @@ Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice sl
trx.state(), lock); trx.state(), lock);
// get the previous revision // get the previous revision
Result res = lookupDocument(&trx, key, previous); LocalDocumentId const oldDocumentId = lookupDocument(&trx, key, previousMdr);
if (oldDocumentId.empty()) {
if (res.fail()) { return Result(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
return res;
} }
VPackSlice const oldDoc(previous.vpack()); VPackSlice const oldDoc(previousMdr.vpack());
LocalDocumentId const oldDocumentId = previous.localDocumentId(); TRI_ASSERT(previousMdr.revisionId() != 0);
TRI_voc_rid_t oldRevisionId =
arangodb::transaction::helpers::extractRevFromDocument(oldDoc);
prevRev = oldRevisionId;
Result res;
// Check old revision: // Check old revision:
if (!options.ignoreRevs && slice.isObject()) { if (!options.ignoreRevs && slice.isObject()) {
TRI_voc_rid_t expectedRevisionId = TRI_ExtractRevisionId(slice); TRI_voc_rid_t expectedRevisionId = TRI_ExtractRevisionId(slice);
res = checkRevision(&trx, expectedRevisionId, oldRevisionId); res = checkRevision(&trx, expectedRevisionId, previousMdr.revisionId());
if (res.fail()) { if (res.fail()) {
return res; return res;
@ -3767,7 +3769,7 @@ Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice sl
->addOperation(documentId, revisionId, operation, marker, options.waitForSync); ->addOperation(documentId, revisionId, operation, marker, options.waitForSync);
if (res.ok() && callbackDuringLock != nullptr) { if (res.ok() && callbackDuringLock != nullptr) {
res = callbackDuringLock(); callbackDuringLock();
} }
} catch (basics::Exception const& ex) { } catch (basics::Exception const& ex) {
res = Result(ex.code(), ex.what()); res = Result(ex.code(), ex.what());
@ -3781,9 +3783,6 @@ Result MMFilesCollection::remove(transaction::Methods& trx, velocypack::Slice sl
if (res.fail()) { if (res.fail()) {
operation.revert(&trx); operation.revert(&trx);
} else {
// store the tick that was used for removing the document
resultMarkerTick = operation.tick();
} }
return res; return res;
} }
@ -3950,23 +3949,21 @@ Result MMFilesCollection::removeFastPath(transaction::Methods& trx, TRI_voc_rid_
/// @brief looks up a document by key, low level worker /// @brief looks up a document by key, low level worker
/// the caller must make sure the read lock on the collection is held /// the caller must make sure the read lock on the collection is held
/// the key must be a string slice, no revision check is performed /// the key must be a string slice, no revision check is performed
Result MMFilesCollection::lookupDocument(transaction::Methods* trx, VPackSlice key, LocalDocumentId MMFilesCollection::lookupDocument(transaction::Methods* trx,
VPackSlice key,
ManagedDocumentResult& result) { ManagedDocumentResult& result) {
if (!key.isString()) { TRI_ASSERT(key.isString());
return Result(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
}
MMFilesSimpleIndexElement element = primaryIndex()->lookupKey(trx, key, result); MMFilesSimpleIndexElement element = primaryIndex()->lookupKey(trx, key, result);
if (element) { if (element) {
LocalDocumentId const documentId = element.localDocumentId(); LocalDocumentId const documentId = element.localDocumentId();
uint8_t const* vpack = lookupDocumentVPack(documentId); uint8_t const* vpack = lookupDocumentVPack(documentId);
if (vpack != nullptr) { if (vpack != nullptr) {
result.setUnmanaged(vpack, documentId); result.setUnmanaged(vpack);
} }
return Result(TRI_ERROR_NO_ERROR); return documentId;
} }
return Result(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND); return LocalDocumentId();
} }
/// @brief updates an existing document, low level worker /// @brief updates an existing document, low level worker

View File

@ -301,26 +301,23 @@ class MMFilesCollection final : public PhysicalCollection {
TRI_voc_tick_t maxTick, ManagedDocumentResult& result); TRI_voc_tick_t maxTick, ManagedDocumentResult& result);
Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& resultMdr,
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, OperationOptions& options,
bool lock, TRI_voc_tick_t& revisionId, KeyLockInfo* keyLockInfo, bool lock, KeyLockInfo* keyLockInfo,
std::function<Result(void)> const& callbackDuringLock) override; std::function<void()> const& callbackDuringLock) override;
Result update(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result update(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, ManagedDocumentResult& previousMdr) override;
ManagedDocumentResult& previous) override;
Result replace(transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result replace(transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previousMdr) override;
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) override;
Result remove(transaction::Methods& trx, velocypack::Slice slice, Result remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previousMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_rid_t& revisionId, KeyLockInfo* keyLockInfo, std::function<void()> const& callbackDuringLock) override;
std::function<Result(void)> const& callbackDuringLock) override;
Result rollbackOperation(transaction::Methods& trx, TRI_voc_document_operation_e type, Result rollbackOperation(transaction::Methods& trx, TRI_voc_document_operation_e type,
LocalDocumentId const& oldDocumentId, LocalDocumentId const& oldDocumentId,
@ -445,7 +442,7 @@ class MMFilesCollection final : public PhysicalCollection {
Result deleteSecondaryIndexes(transaction::Methods& trx, LocalDocumentId const& documentId, Result deleteSecondaryIndexes(transaction::Methods& trx, LocalDocumentId const& documentId,
velocypack::Slice const& doc, Index::OperationMode mode); velocypack::Slice const& doc, Index::OperationMode mode);
Result lookupDocument(transaction::Methods*, velocypack::Slice, LocalDocumentId lookupDocument(transaction::Methods*, velocypack::Slice,
ManagedDocumentResult& result); ManagedDocumentResult& result);
Result updateDocument(transaction::Methods& trx, TRI_voc_rid_t revisionId, Result updateDocument(transaction::Methods& trx, TRI_voc_rid_t revisionId,

View File

@ -35,13 +35,12 @@ using namespace arangodb;
MMFilesDocumentOperation::MMFilesDocumentOperation(LogicalCollection* collection, MMFilesDocumentOperation::MMFilesDocumentOperation(LogicalCollection* collection,
TRI_voc_document_operation_e type) TRI_voc_document_operation_e type)
: _collection(collection), _tick(0), _type(type), _status(StatusType::CREATED) {} : _collection(collection), _type(type), _status(StatusType::CREATED) {}
MMFilesDocumentOperation::~MMFilesDocumentOperation() {} MMFilesDocumentOperation::~MMFilesDocumentOperation() {}
MMFilesDocumentOperation* MMFilesDocumentOperation::clone() { MMFilesDocumentOperation* MMFilesDocumentOperation::clone() {
MMFilesDocumentOperation* copy = new MMFilesDocumentOperation(_collection, _type); MMFilesDocumentOperation* copy = new MMFilesDocumentOperation(_collection, _type);
copy->_tick = _tick;
copy->_oldRevision = _oldRevision; copy->_oldRevision = _oldRevision;
copy->_newRevision = _newRevision; copy->_newRevision = _newRevision;
copy->_status = _status; copy->_status = _status;

View File

@ -76,9 +76,6 @@ struct MMFilesDocumentOperation {
void setVPack(uint8_t const* vpack); void setVPack(uint8_t const* vpack);
void setTick(TRI_voc_tick_t tick) { _tick = tick; }
TRI_voc_tick_t tick() const { return _tick; }
TRI_voc_document_operation_e type() const { return _type; } TRI_voc_document_operation_e type() const { return _type; }
LogicalCollection* collection() const { return _collection; } LogicalCollection* collection() const { return _collection; }
@ -101,7 +98,6 @@ struct MMFilesDocumentOperation {
LogicalCollection* _collection; LogicalCollection* _collection;
MMFilesDocumentDescriptor _oldRevision; MMFilesDocumentDescriptor _oldRevision;
MMFilesDocumentDescriptor _newRevision; MMFilesDocumentDescriptor _newRevision;
TRI_voc_tick_t _tick;
TRI_voc_document_operation_e _type; TRI_voc_document_operation_e _type;
StatusType _status; StatusType _status;
}; };

View File

@ -40,7 +40,7 @@ uint8_t const* MMFilesIndexLookupContext::lookup(LocalDocumentId token) const {
try { try {
uint8_t const* vpack = static_cast<MMFilesCollection*>(_collection->getPhysical())->lookupDocumentVPack(token); uint8_t const* vpack = static_cast<MMFilesCollection*>(_collection->getPhysical())->lookupDocumentVPack(token);
if (vpack != nullptr && _result != nullptr) { if (vpack != nullptr && _result != nullptr) {
_result->setUnmanaged(vpack, token); _result->setUnmanaged(vpack);
} }
return vpack; return vpack;
} catch (...) { } catch (...) {

View File

@ -33,6 +33,8 @@
#include "MMFiles/MMFilesLogfileManager.h" #include "MMFiles/MMFilesLogfileManager.h"
#include "MMFiles/MMFilesPersistentIndexFeature.h" #include "MMFiles/MMFilesPersistentIndexFeature.h"
#include "MMFiles/MMFilesTransactionCollection.h" #include "MMFiles/MMFilesTransactionCollection.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "StorageEngine/TransactionCollection.h" #include "StorageEngine/TransactionCollection.h"
#include "Transaction/Methods.h" #include "Transaction/Methods.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
@ -56,7 +58,8 @@ MMFilesTransactionState::MMFilesTransactionState(TRI_vocbase_t& vocbase, TRI_voc
: TransactionState(vocbase, tid, options), : TransactionState(vocbase, tid, options),
_rocksTransaction(nullptr), _rocksTransaction(nullptr),
_beginWritten(false), _beginWritten(false),
_hasOperations(false) {} _hasOperations(false),
_lastWrittenOperationTick(0) {}
/// @brief free a transaction container /// @brief free a transaction container
MMFilesTransactionState::~MMFilesTransactionState() { MMFilesTransactionState::~MMFilesTransactionState() {
@ -285,7 +288,8 @@ int MMFilesTransactionState::addOperation(LocalDocumentId const& documentId,
} }
} }
operation.setTick(slotInfo.tick); _lastWrittenOperationTick = slotInfo.tick;
fid = slotInfo.logfileId; fid = slotInfo.logfileId;
position = slotInfo.mem; position = slotInfo.mem;
} else { } else {
@ -469,6 +473,10 @@ int MMFilesTransactionState::writeAbortMarker() {
/// @brief write WAL commit marker /// @brief write WAL commit marker
int MMFilesTransactionState::writeCommitMarker() { int MMFilesTransactionState::writeCommitMarker() {
if (!needWriteMarker(false)) { if (!needWriteMarker(false)) {
if (_options.waitForSync && _lastWrittenOperationTick > 0 &&
isSingleOperation()) { // we do the waitForSync in the end
EngineSelectorFeature::ENGINE->waitForSyncTick(_lastWrittenOperationTick);
}
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }

View File

@ -97,9 +97,14 @@ class MMFilesTransactionState final : public TransactionState {
/// @brief free all operations for a transaction /// @brief free all operations for a transaction
void freeOperations(transaction::Methods* activeTrx); void freeOperations(transaction::Methods* activeTrx);
private:
rocksdb::Transaction* _rocksTransaction; rocksdb::Transaction* _rocksTransaction;
bool _beginWritten; bool _beginWritten;
bool _hasOperations; bool _hasOperations;
/// @brief tick of last added & written operation
TRI_voc_tick_t _lastWrittenOperationTick;
}; };
} // namespace arangodb } // namespace arangodb

View File

@ -569,7 +569,7 @@ Result buildHttpError(httpclient::SimpleHttpResult* response,
if (response == nullptr || !response->isComplete()) { if (response == nullptr || !response->isComplete()) {
std::string errorMsg; std::string errorMsg;
connection.lease([&errorMsg, &response](httpclient::SimpleHttpClient* client) { connection.lease([&errorMsg](httpclient::SimpleHttpClient* client) {
errorMsg = client->getErrorMessage(); errorMsg = client->getErrorMessage();
}); });
if (errorMsg.empty() && response != nullptr) { if (errorMsg.empty() && response != nullptr) {

View File

@ -392,16 +392,16 @@ std::shared_ptr<Index> RocksDBCollection::createIndex(VPackSlice const& info,
RocksDBKey key; // read collection info from database RocksDBKey key; // read collection info from database
key.constructCollection(_logicalCollection.vocbase().id(), key.constructCollection(_logicalCollection.vocbase().id(),
_logicalCollection.id()); _logicalCollection.id());
rocksdb::PinnableSlice value; rocksdb::PinnableSlice ps;
rocksdb::Status s = engine->db()->Get(rocksdb::ReadOptions(), rocksdb::Status s = engine->db()->Get(rocksdb::ReadOptions(),
RocksDBColumnFamily::definitions(), RocksDBColumnFamily::definitions(),
key.string(), &value); key.string(), &ps);
if (!s.ok()) { if (!s.ok()) {
res.reset(rocksutils::convertStatus(s)); res.reset(rocksutils::convertStatus(s));
} else { } else {
VPackBuilder builder; VPackBuilder builder;
builder.openObject(); builder.openObject();
for (auto const& pair : VPackObjectIterator(VPackSlice(value.data()))) { for (auto const& pair : VPackObjectIterator(VPackSlice(ps.data()))) {
if (pair.key.isEqualString("indexes")) { // append new index if (pair.key.isEqualString("indexes")) { // append new index
VPackArrayBuilder arrGuard(&builder, "indexes"); VPackArrayBuilder arrGuard(&builder, "indexes");
builder.add(VPackArrayIterator(pair.value)); builder.add(VPackArrayIterator(pair.value));
@ -790,10 +790,20 @@ Result RocksDBCollection::read(transaction::Methods* trx,
ManagedDocumentResult& result, bool /*lock*/) { ManagedDocumentResult& result, bool /*lock*/) {
LocalDocumentId const documentId = primaryIndex()->lookupKey(trx, key); LocalDocumentId const documentId = primaryIndex()->lookupKey(trx, key);
if (!documentId.isSet()) { if (!documentId.isSet()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND); return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
} // found
std::string* buffer = result.setManaged();
rocksdb::PinnableSlice ps(buffer);
Result res = lookupDocumentVPack(trx, documentId, ps, /*readCache*/true, /*fillCache*/true);
if (res.ok()) {
if (ps.IsPinned()) {
buffer->assign(ps.data(), ps.size());
} // else value is already assigned
result.setRevisionId(); // extracts id from buffer
} }
// found
return lookupDocumentVPack(documentId, trx, result, /*withCache*/true); return res;
} }
// read using a token! // read using a token!
@ -801,8 +811,15 @@ bool RocksDBCollection::readDocument(transaction::Methods* trx,
LocalDocumentId const& documentId, LocalDocumentId const& documentId,
ManagedDocumentResult& result) const { ManagedDocumentResult& result) const {
if (documentId.isSet()) { if (documentId.isSet()) {
auto res = lookupDocumentVPack(documentId, trx, result, /*withCache*/true); std::string* buffer = result.setManaged();
return res.ok(); rocksdb::PinnableSlice ps(buffer);
Result res = lookupDocumentVPack(trx, documentId, ps, /*readCache*/true, /*fillCache*/true);
if (res.ok()) {
if (ps.IsPinned()) {
buffer->assign(ps.data(), ps.size());
} // else value is already assigned
return true;
}
} }
return false; return false;
} }
@ -812,33 +829,29 @@ bool RocksDBCollection::readDocumentWithCallback(transaction::Methods* trx,
LocalDocumentId const& documentId, LocalDocumentId const& documentId,
IndexIterator::DocumentCallback const& cb) const { IndexIterator::DocumentCallback const& cb) const {
if (documentId.isSet()) { if (documentId.isSet()) {
return lookupDocumentVPack(documentId, trx, cb, true).ok(); return lookupDocumentVPack(trx, documentId, cb, /*withCache*/true);
} }
return false; return false;
} }
Result RocksDBCollection::insert(arangodb::transaction::Methods* trx, Result RocksDBCollection::insert(arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice const slice, arangodb::velocypack::Slice const slice,
arangodb::ManagedDocumentResult& mdr, arangodb::ManagedDocumentResult& resultMdr,
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, OperationOptions& options,
bool, TRI_voc_tick_t& revisionId, KeyLockInfo* /*keyLockInfo*/, bool /*lock*/, KeyLockInfo* /*keyLockInfo*/,
std::function<Result(void)> const& callbackDuringLock) { std::function<void()> const& cbDuringLock) {
// store the tick that was used for writing the document
// note that we don't need it for this engine
resultMarkerTick = 0;
bool const isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type()); bool const isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type());
transaction::BuilderLeaser builder(trx); transaction::BuilderLeaser builder(trx);
TRI_voc_tick_t revisionId;
Result res(newObjectForInsert(trx, slice, isEdgeCollection, *builder.get(), Result res(newObjectForInsert(trx, slice, isEdgeCollection, *builder.get(),
options.isRestore, revisionId)); options.isRestore, revisionId));
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
VPackSlice newSlice = builder->slice(); VPackSlice newSlice = builder->slice();
if (options.overwrite) { if (options.overwrite) {
// special optimization for the overwrite case: // special optimization for the overwrite case:
// in case the operation is a RepSert, we will first check if the specified // in case the operation is a RepSert, we will first check if the specified
@ -879,25 +892,27 @@ Result RocksDBCollection::insert(arangodb::transaction::Methods* trx,
if (res.ok()) { if (res.ok()) {
trackWaitForSync(trx, options); trackWaitForSync(trx, options);
if (options.silent) {
mdr.clear(); if (options.returnNew) {
} else { resultMdr.setManaged(newSlice.begin());
mdr.setManaged(newSlice.begin(), documentId); TRI_ASSERT(resultMdr.revisionId() == revisionId);
TRI_ASSERT(!mdr.empty()); } else if(!options.silent) { // need to pass revId manually
transaction::BuilderLeaser keyBuilder(trx);
keyBuilder->openObject(/*unindexed*/true);
keyBuilder->add(StaticStrings::KeyString, transaction::helpers::extractKeyFromDocument(newSlice));
keyBuilder->close();
resultMdr.setManaged()->assign(reinterpret_cast<char const*>(keyBuilder->start()),
keyBuilder->size());
resultMdr.setRevisionId(revisionId);
} }
bool hasPerformedIntermediateCommit = false; bool hasPerformedIntermediateCommit = false;
res = state->addOperation(_logicalCollection.id(), revisionId,
auto result = state->addOperation(_logicalCollection.id(), revisionId,
TRI_VOC_DOCUMENT_OPERATION_INSERT, TRI_VOC_DOCUMENT_OPERATION_INSERT,
hasPerformedIntermediateCommit); hasPerformedIntermediateCommit);
if (result.ok() && callbackDuringLock != nullptr) { if (res.ok() && cbDuringLock != nullptr) {
result = callbackDuringLock(); cbDuringLock();
}
if (result.fail()) {
THROW_ARANGO_EXCEPTION(result);
} }
guard.finish(hasPerformedIntermediateCommit); guard.finish(hasPerformedIntermediateCommit);
@ -908,50 +923,46 @@ Result RocksDBCollection::insert(arangodb::transaction::Methods* trx,
Result RocksDBCollection::update(arangodb::transaction::Methods* trx, Result RocksDBCollection::update(arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
ManagedDocumentResult& mdr, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool /*lock*/, bool /*lock*/, ManagedDocumentResult& previousMdr) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
resultMarkerTick = 0;
VPackSlice key = newSlice.get(StaticStrings::KeyString); VPackSlice keySlice = newSlice.get(StaticStrings::KeyString);
if (key.isNone()) { if (keySlice.isNone()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); return TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
} else if (!keySlice.isString()) {
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
} }
LocalDocumentId const newDocumentId = LocalDocumentId::create(); auto const oldDocumentId = primaryIndex()->lookupKey(trx, VPackStringRef(keySlice));
auto isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type()); if (!oldDocumentId.isSet()) {
return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
Result res = this->read(trx, key, previous, /*lock*/ false); }
std::string* prevBuffer = previousMdr.setManaged();
// uses either prevBuffer or avoids memcpy (if read hits block cache)
rocksdb::PinnableSlice previousPS(prevBuffer);
Result res = lookupDocumentVPack(trx, oldDocumentId, previousPS,
/*readCache*/true, /*fillCache*/false);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
TRI_ASSERT(!previous.empty()); TRI_ASSERT(previousPS.size() > 0);
LocalDocumentId const oldDocumentId = previous.localDocumentId(); VPackSlice const oldDoc(previousPS.data());
VPackSlice oldDoc(previous.vpack()); previousMdr.setRevisionId(transaction::helpers::extractRevFromDocument(oldDoc));
TRI_voc_rid_t const oldRevisionId = transaction::helpers::extractRevFromDocument(oldDoc); TRI_ASSERT(previousMdr.revisionId() != 0);
prevRev = oldRevisionId;
// Check old revision:
if (!options.ignoreRevs) {
TRI_voc_rid_t expectedRev = 0;
if (newSlice.isObject()) {
expectedRev = TRI_ExtractRevisionId(newSlice);
}
int result = checkRevision(trx, expectedRev, prevRev);
if (!options.ignoreRevs) { // Check old revision:
TRI_voc_rid_t expectedRev = TRI_ExtractRevisionId(newSlice);
int result = checkRevision(trx, expectedRev, previousMdr.revisionId());
if (result != TRI_ERROR_NO_ERROR) { if (result != TRI_ERROR_NO_ERROR) {
return res.reset(result); return res.reset(result);
} }
} }
if (newSlice.length() <= 1) { if (newSlice.length() <= 1) { // TODO move above ?!
// shortcut. no need to do anything // shortcut. no need to do anything
mdr = previous; resultMdr.setManaged(oldDoc.begin());
TRI_ASSERT(!mdr.empty()); TRI_ASSERT(!resultMdr.empty());
trackWaitForSync(trx, options); trackWaitForSync(trx, options);
return res; return res;
@ -959,11 +970,13 @@ Result RocksDBCollection::update(arangodb::transaction::Methods* trx,
// merge old and new values // merge old and new values
TRI_voc_rid_t revisionId; TRI_voc_rid_t revisionId;
LocalDocumentId const newDocumentId = LocalDocumentId::create();
auto isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type());
transaction::BuilderLeaser builder(trx); transaction::BuilderLeaser builder(trx);
res = mergeObjectsForUpdate(trx, oldDoc, newSlice, isEdgeCollection, res = mergeObjectsForUpdate(trx, oldDoc, newSlice, isEdgeCollection,
options.mergeObjects, options.keepNull, options.mergeObjects, options.keepNull,
*builder.get(), options.isRestore, revisionId); *builder.get(), options.isRestore, revisionId);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
@ -974,15 +987,14 @@ Result RocksDBCollection::update(arangodb::transaction::Methods* trx,
return res.reset(TRI_ERROR_CLUSTER_MUST_NOT_CHANGE_SHARDING_ATTRIBUTES); return res.reset(TRI_ERROR_CLUSTER_MUST_NOT_CHANGE_SHARDING_ATTRIBUTES);
} }
if (arangodb::smartJoinAttributeChanged(_logicalCollection, oldDoc, builder->slice(), true)) { if (arangodb::smartJoinAttributeChanged(_logicalCollection, oldDoc, builder->slice(), true)) {
return Result(TRI_ERROR_CLUSTER_MUST_NOT_CHANGE_SMART_JOIN_ATTRIBUTE); return res.reset(TRI_ERROR_CLUSTER_MUST_NOT_CHANGE_SMART_JOIN_ATTRIBUTE);
} }
} }
VPackSlice const newDoc(builder->slice()); VPackSlice const newDoc(builder->slice());
auto* state = RocksDBTransactionState::toState(trx);
RocksDBSavePoint guard(trx, TRI_VOC_DOCUMENT_OPERATION_UPDATE); RocksDBSavePoint guard(trx, TRI_VOC_DOCUMENT_OPERATION_UPDATE);
auto* state = RocksDBTransactionState::toState(trx);
// add possible log statement under guard // add possible log statement under guard
state->prepareOperation(_logicalCollection.id(), revisionId, TRI_VOC_DOCUMENT_OPERATION_UPDATE); state->prepareOperation(_logicalCollection.id(), revisionId, TRI_VOC_DOCUMENT_OPERATION_UPDATE);
res = updateDocument(trx, oldDocumentId, oldDoc, newDocumentId, newDoc, options); res = updateDocument(trx, oldDocumentId, oldDoc, newDocumentId, newDoc, options);
@ -990,15 +1002,22 @@ Result RocksDBCollection::update(arangodb::transaction::Methods* trx,
if (res.ok()) { if (res.ok()) {
trackWaitForSync(trx, options); trackWaitForSync(trx, options);
if (options.silent) { if (options.returnNew) {
mdr.clear(); resultMdr.setManaged(newDoc.begin());
TRI_ASSERT(!resultMdr.empty());
} else { // need to pass revId manually
resultMdr.setRevisionId(revisionId);
}
if (options.returnOld) {
if (previousPS.IsPinned()) { // value was not copied
prevBuffer->assign(previousPS.data(), previousPS.size());
} // else value is already assigned
TRI_ASSERT(!previousMdr.empty());
} else { } else {
mdr.setManaged(newDoc.begin(), newDocumentId); previousMdr.clearData();
TRI_ASSERT(!mdr.empty());
} }
bool hasPerformedIntermediateCommit = false; bool hasPerformedIntermediateCommit = false;
auto result = state->addOperation(_logicalCollection.id(), revisionId, auto result = state->addOperation(_logicalCollection.id(), revisionId,
TRI_VOC_DOCUMENT_OPERATION_UPDATE, TRI_VOC_DOCUMENT_OPERATION_UPDATE,
hasPerformedIntermediateCommit); hasPerformedIntermediateCommit);
@ -1014,42 +1033,37 @@ Result RocksDBCollection::update(arangodb::transaction::Methods* trx,
Result RocksDBCollection::replace(transaction::Methods* trx, Result RocksDBCollection::replace(transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
ManagedDocumentResult& mdr, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool, bool /*lock*/, ManagedDocumentResult& previousMdr) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
resultMarkerTick = 0;
// get the previous revision VPackSlice keySlice = newSlice.get(StaticStrings::KeyString);
VPackSlice key = newSlice.get(StaticStrings::KeyString); if (keySlice.isNone()) {
Result res; return TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD;
if (key.isNone()) { } else if (!keySlice.isString()) {
return res.reset(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
} }
LocalDocumentId const newDocumentId = LocalDocumentId::create(); auto const oldDocumentId = primaryIndex()->lookupKey(trx, VPackStringRef(keySlice));
bool const isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type()); if (!oldDocumentId.isSet()) {
return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
// get the previous revision }
res = this->read(trx, key, previous, /*lock*/ false); std::string* prevBuffer = previousMdr.setManaged();
// uses either prevBuffer or avoids memcpy (if read hits block cache)
rocksdb::PinnableSlice previousPS(prevBuffer);
Result res = lookupDocumentVPack(trx, oldDocumentId, previousPS,
/*readCache*/true, /*fillCache*/false);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
TRI_ASSERT(!previous.empty()); TRI_ASSERT(previousPS.size() > 0);
LocalDocumentId const oldDocumentId = previous.localDocumentId(); VPackSlice const oldDoc(previousPS.data());
previousMdr.setRevisionId(transaction::helpers::extractRevFromDocument(oldDoc));
TRI_ASSERT(previousMdr.revisionId() != 0);
VPackSlice oldDoc(previous.vpack()); if (!options.ignoreRevs) { // Check old revision:
TRI_voc_rid_t oldRevisionId = transaction::helpers::extractRevFromDocument(oldDoc); TRI_voc_rid_t expectedRev = TRI_ExtractRevisionId(newSlice);
prevRev = oldRevisionId; res = checkRevision(trx, expectedRev, previousMdr.revisionId());
// Check old revision:
if (!options.ignoreRevs) {
TRI_voc_rid_t expectedRev = 0;
if (newSlice.isObject()) {
expectedRev = TRI_ExtractRevisionId(newSlice);
}
res = checkRevision(trx, expectedRev, prevRev);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
@ -1057,10 +1071,12 @@ Result RocksDBCollection::replace(transaction::Methods* trx,
// merge old and new values // merge old and new values
TRI_voc_rid_t revisionId; TRI_voc_rid_t revisionId;
LocalDocumentId const newDocumentId = LocalDocumentId::create();
bool const isEdgeCollection = (TRI_COL_TYPE_EDGE == _logicalCollection.type());
transaction::BuilderLeaser builder(trx); transaction::BuilderLeaser builder(trx);
res = newObjectForReplace(trx, oldDoc, newSlice, isEdgeCollection, res = newObjectForReplace(trx, oldDoc, newSlice, isEdgeCollection,
*builder.get(), options.isRestore, revisionId); *builder.get(), options.isRestore, revisionId);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
@ -1076,27 +1092,32 @@ Result RocksDBCollection::replace(transaction::Methods* trx,
} }
VPackSlice const newDoc(builder->slice()); VPackSlice const newDoc(builder->slice());
auto* state = RocksDBTransactionState::toState(trx);
RocksDBSavePoint guard(trx, TRI_VOC_DOCUMENT_OPERATION_REPLACE); RocksDBSavePoint guard(trx, TRI_VOC_DOCUMENT_OPERATION_REPLACE);
auto* state = RocksDBTransactionState::toState(trx);
// add possible log statement under guard // add possible log statement under guard
state->prepareOperation(_logicalCollection.id(), revisionId, TRI_VOC_DOCUMENT_OPERATION_REPLACE); state->prepareOperation(_logicalCollection.id(), revisionId, TRI_VOC_DOCUMENT_OPERATION_REPLACE);
res = updateDocument(trx, oldDocumentId, oldDoc, newDocumentId, newDoc, options); res = updateDocument(trx, oldDocumentId, oldDoc, newDocumentId, newDoc, options);
if (res.ok()) { if (res.ok()) {
trackWaitForSync(trx, options); trackWaitForSync(trx, options);
if (options.silent) { if (options.returnNew) {
mdr.clear(); resultMdr.setManaged(newDoc.begin());
TRI_ASSERT(!resultMdr.empty());
} else { // need to pass revId manually
resultMdr.setRevisionId(revisionId);
}
if (options.returnOld) {
if (previousPS.IsPinned()) { // value was not copied
prevBuffer->assign(previousPS.data(), previousPS.size());
} // else value is already assigned
TRI_ASSERT(!previousMdr.empty());
} else { } else {
mdr.setManaged(newDoc.begin(), newDocumentId); previousMdr.clearData();
TRI_ASSERT(!mdr.empty());
} }
bool hasPerformedIntermediateCommit = false; bool hasPerformedIntermediateCommit = false;
auto result = state->addOperation(_logicalCollection.id(), revisionId, auto result = state->addOperation(_logicalCollection.id(), revisionId,
TRI_VOC_DOCUMENT_OPERATION_REPLACE, TRI_VOC_DOCUMENT_OPERATION_REPLACE,
hasPerformedIntermediateCommit); hasPerformedIntermediateCommit);
@ -1112,44 +1133,43 @@ Result RocksDBCollection::replace(transaction::Methods* trx,
} }
Result RocksDBCollection::remove(transaction::Methods& trx, velocypack::Slice slice, Result RocksDBCollection::remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previousMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool /*lock*/, bool /*lock*/, KeyLockInfo* /*keyLockInfo*/,
TRI_voc_rid_t& prevRev, TRI_voc_rid_t& revisionId, std::function<void()> const& cbDuringLock) {
KeyLockInfo* /*keyLockInfo*/,
std::function<Result(void)> const& callbackDuringLock) {
// store the tick that was used for writing the document
// note that we don't need it for this engine
resultMarkerTick = 0;
prevRev = 0;
revisionId = newRevisionId();
VPackSlice key; VPackSlice keySlice;
if (slice.isString()) { if (slice.isString()) {
key = slice; keySlice = slice;
} else { } else {
key = slice.get(StaticStrings::KeyString); keySlice = slice.get(StaticStrings::KeyString);
}
TRI_ASSERT(!keySlice.isNone());
if (!keySlice.isString()) {
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
} }
TRI_ASSERT(!key.isNone());
// get the previous revision
Result res = this->read(&trx, key, previous, /*lock*/ false);
auto const documentId = primaryIndex()->lookupKey(&trx, VPackStringRef(keySlice));
if (!documentId.isSet()) {
return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
}
std::string* prevBuffer = previousMdr.setManaged();
// uses either prevBuffer or avoids memcpy (if read hits block cache)
rocksdb::PinnableSlice previousPS(prevBuffer);
Result res = lookupDocumentVPack(&trx, documentId, previousPS,
/*readCache*/true, /*fillCache*/false);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
TRI_ASSERT(!previous.empty()); TRI_ASSERT(previousPS.size() > 0);
LocalDocumentId const oldDocumentId = previous.localDocumentId(); VPackSlice const oldDoc(previousPS.data());
previousMdr.setRevisionId(transaction::helpers::extractRevFromDocument(oldDoc));
VPackSlice oldDoc(previous.vpack()); TRI_ASSERT(previousMdr.revisionId() != 0);
TRI_voc_rid_t oldRevisionId =
arangodb::transaction::helpers::extractRevFromDocument(oldDoc);
prevRev = oldRevisionId;
// Check old revision: // Check old revision:
if (!options.ignoreRevs && slice.isObject()) { if (!options.ignoreRevs && slice.isObject()) {
TRI_voc_rid_t expectedRevisionId = TRI_ExtractRevisionId(slice); TRI_voc_rid_t expectedRevisionId = TRI_ExtractRevisionId(slice);
res = checkRevision(&trx, expectedRevisionId, oldRevisionId); res = checkRevision(&trx, expectedRevisionId, previousMdr.revisionId());
if (res.fail()) { if (res.fail()) {
return res; return res;
@ -1160,24 +1180,28 @@ Result RocksDBCollection::remove(transaction::Methods& trx, velocypack::Slice sl
RocksDBSavePoint guard(&trx, TRI_VOC_DOCUMENT_OPERATION_REMOVE); RocksDBSavePoint guard(&trx, TRI_VOC_DOCUMENT_OPERATION_REMOVE);
// add possible log statement under guard // add possible log statement under guard
state->prepareOperation(_logicalCollection.id(), oldRevisionId, state->prepareOperation(_logicalCollection.id(), previousMdr.revisionId(),
TRI_VOC_DOCUMENT_OPERATION_REMOVE); TRI_VOC_DOCUMENT_OPERATION_REMOVE);
res = removeDocument(&trx, oldDocumentId, oldDoc, options); res = removeDocument(&trx, documentId, oldDoc, options);
if (res.ok()) { if (res.ok()) {
trackWaitForSync(&trx, options); trackWaitForSync(&trx, options);
bool hasPerformedIntermediateCommit = false; if (options.returnOld) {
if (previousPS.IsPinned()) { // value was not copied
res = state->addOperation(_logicalCollection.id(), revisionId, TRI_VOC_DOCUMENT_OPERATION_REMOVE, prevBuffer->assign(previousPS.data(), previousPS.size());
hasPerformedIntermediateCommit); } // else value is already assigned
TRI_ASSERT(!previousMdr.empty());
if (res.ok() && callbackDuringLock != nullptr) { } else {
res = callbackDuringLock(); previousMdr.clearData();
} }
if (res.fail()) { bool hasPerformedIntermediateCommit = false;
THROW_ARANGO_EXCEPTION(res); res = state->addOperation(_logicalCollection.id(), newRevisionId(), TRI_VOC_DOCUMENT_OPERATION_REMOVE,
hasPerformedIntermediateCommit);
if (res.ok() && cbDuringLock != nullptr) {
cbDuringLock();
} }
guard.finish(hasPerformedIntermediateCommit); guard.finish(hasPerformedIntermediateCommit);
@ -1355,10 +1379,14 @@ Result RocksDBCollection::updateDocument(transaction::Methods* trx,
return res; return res;
} }
arangodb::Result RocksDBCollection::lookupDocumentVPack(LocalDocumentId const& documentId, /// @brief lookup document in cache and / or rocksdb
transaction::Methods* trx, /// @param readCache attempt to read from cache
arangodb::ManagedDocumentResult& mdr, /// @param fillCache fill cache with found document
bool withCache) const { arangodb::Result RocksDBCollection::lookupDocumentVPack(transaction::Methods* trx,
LocalDocumentId const& documentId,
rocksdb::PinnableSlice& ps,
bool readCache,
bool fillCache) const {
TRI_ASSERT(trx->state()->isRunning()); TRI_ASSERT(trx->state()->isRunning());
TRI_ASSERT(_objectId != 0); TRI_ASSERT(_objectId != 0);
Result res; Result res;
@ -1367,15 +1395,15 @@ arangodb::Result RocksDBCollection::lookupDocumentVPack(LocalDocumentId const& d
key->constructDocument(_objectId, documentId); key->constructDocument(_objectId, documentId);
bool lockTimeout = false; bool lockTimeout = false;
if (withCache && useCache()) { if (readCache && useCache()) {
TRI_ASSERT(_cache != nullptr); TRI_ASSERT(_cache != nullptr);
// check cache first for fast path // check cache first for fast path
auto f = _cache->find(key->string().data(), auto f = _cache->find(key->string().data(),
static_cast<uint32_t>(key->string().size())); static_cast<uint32_t>(key->string().size()));
if (f.found()) { if (f.found()) { // copy finding into buffer
std::string* value = mdr.setManaged(documentId); ps.PinSelf(rocksdb::Slice(reinterpret_cast<char const*>(f.value()->value()),
value->append(reinterpret_cast<char const*>(f.value()->value()), f.value()->valueSize()));
f.value()->valueSize()); // TODO we could potentially use the PinSlice method ?!
return res; return res;
} }
if (f.result().errorNumber() == TRI_ERROR_LOCK_TIMEOUT) { if (f.result().errorNumber() == TRI_ERROR_LOCK_TIMEOUT) {
@ -1385,77 +1413,17 @@ arangodb::Result RocksDBCollection::lookupDocumentVPack(LocalDocumentId const& d
} }
} }
RocksDBMethods* mthd = RocksDBTransactionState::toMethods(trx);
std::string* value = mdr.setManaged(documentId);
rocksdb::Status s = mthd->Get(RocksDBColumnFamily::documents(), key->string(), value);
if (s.ok()) {
if (withCache && useCache() && !lockTimeout) {
TRI_ASSERT(_cache != nullptr);
// write entry back to cache
auto entry =
cache::CachedValue::construct(key->string().data(),
static_cast<uint32_t>(key->string().size()),
value->data(),
static_cast<uint64_t>(value->size()));
if (entry) {
Result status = _cache->insert(entry);
if (status.errorNumber() == TRI_ERROR_LOCK_TIMEOUT) {
// the writeLock uses cpu_relax internally, so we can try yield
std::this_thread::yield();
status = _cache->insert(entry);
}
if (status.fail()) {
delete entry;
}
}
}
} else {
LOG_TOPIC("bd363", DEBUG, Logger::ENGINES)
<< "NOT FOUND rev: " << documentId.id() << " trx: " << trx->state()->id()
<< " objectID " << _objectId << " name: " << _logicalCollection.name();
mdr.clear();
res.reset(rocksutils::convertStatus(s, rocksutils::document));
}
return res;
}
arangodb::Result RocksDBCollection::lookupDocumentVPack(
LocalDocumentId const& documentId, transaction::Methods* trx,
IndexIterator::DocumentCallback const& cb, bool withCache) const {
TRI_ASSERT(trx->state()->isRunning());
TRI_ASSERT(_objectId != 0);
Result res;
RocksDBKeyLeaser key(trx);
key->constructDocument(_objectId, documentId);
bool lockTimeout = false;
if (withCache && useCache()) {
TRI_ASSERT(_cache != nullptr);
// check cache first for fast path
auto f = _cache->find(key->string().data(),
static_cast<uint32_t>(key->string().size()));
if (f.found()) {
cb(documentId, VPackSlice(reinterpret_cast<char const*>(f.value()->value())));
return res;
}
if (f.result().errorNumber() == TRI_ERROR_LOCK_TIMEOUT) {
// assuming someone is currently holding a write lock, which
// is why we cannot access the TransactionalBucket.
lockTimeout = true; // we skip the insert in this case
}
}
rocksdb::PinnableSlice ps;
RocksDBMethods* mthd = RocksDBTransactionState::toMethods(trx); RocksDBMethods* mthd = RocksDBTransactionState::toMethods(trx);
rocksdb::Status s = mthd->Get(RocksDBColumnFamily::documents(), key->string(), &ps); rocksdb::Status s = mthd->Get(RocksDBColumnFamily::documents(), key->string(), &ps);
if (s.ok()) { if (!s.ok()) {
if (withCache && useCache() && !lockTimeout) { LOG_TOPIC("f63dd", DEBUG, Logger::ENGINES)
<< "NOT FOUND rev: " << documentId.id() << " trx: " << trx->state()->id()
<< " objectID " << _objectId << " name: " << _logicalCollection.name();
return res.reset(rocksutils::convertStatus(s, rocksutils::document));
}
if (fillCache && useCache() && !lockTimeout) {
TRI_ASSERT(_cache != nullptr); TRI_ASSERT(_cache != nullptr);
// write entry back to cache // write entry back to cache
auto entry = auto entry =
@ -1475,16 +1443,44 @@ arangodb::Result RocksDBCollection::lookupDocumentVPack(
} }
} }
cb(documentId, VPackSlice(ps.data()));
} else {
LOG_TOPIC("f63dd", DEBUG, Logger::ENGINES)
<< "NOT FOUND rev: " << documentId.id() << " trx: " << trx->state()->id()
<< " objectID " << _objectId << " name: " << _logicalCollection.name();
res.reset(rocksutils::convertStatus(s, rocksutils::document));
}
return res; return res;
} }
bool RocksDBCollection::lookupDocumentVPack(transaction::Methods* trx,
LocalDocumentId const& documentId,
IndexIterator::DocumentCallback const& cb,
bool withCache) const {
bool lockTimeout = false;
if (withCache && useCache()) {
RocksDBKeyLeaser key(trx);
key->constructDocument(_objectId, documentId);
TRI_ASSERT(_cache != nullptr);
// check cache first for fast path
auto f = _cache->find(key->string().data(),
static_cast<uint32_t>(key->string().size()));
if (f.found()) {
cb(documentId, VPackSlice(reinterpret_cast<char const*>(f.value()->value())));
return true;
}
if (f.result().errorNumber() == TRI_ERROR_LOCK_TIMEOUT) {
// assuming someone is currently holding a write lock, which
// is why we cannot access the TransactionalBucket.
lockTimeout = true; // we skip the insert in this case
}
}
transaction::StringLeaser buffer(trx);
rocksdb::PinnableSlice ps(buffer.get());
Result res = lookupDocumentVPack(trx, documentId, ps, /*readCache*/false, withCache);
if (res.ok()) {
TRI_ASSERT(ps.size() > 0);
cb(documentId, VPackSlice(ps.data()));
return true;
}
return false;
}
/// may never be called unless recovery is finished /// may never be called unless recovery is finished
void RocksDBCollection::adjustNumberDocuments(TRI_voc_rid_t revId, int64_t adjustment) { void RocksDBCollection::adjustNumberDocuments(TRI_voc_rid_t revId, int64_t adjustment) {
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE #ifdef ARANGODB_ENABLE_MAINTAINER_MODE

View File

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER /// DISCLAIMER
/// ///
/// Copyright 2014-2017 ArangoDB GmbH, Cologne, Germany /// Copyright 2014-2019 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
/// ///
/// Licensed under the Apache License, Version 2.0 (the "License"); /// Licensed under the Apache License, Version 2.0 (the "License");
@ -32,6 +32,7 @@
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
namespace rocksdb { namespace rocksdb {
class PinnableSlice;
class Transaction; class Transaction;
} }
@ -134,30 +135,27 @@ class RocksDBCollection final : public PhysicalCollection {
bool readDocument(transaction::Methods* trx, LocalDocumentId const& token, bool readDocument(transaction::Methods* trx, LocalDocumentId const& token,
ManagedDocumentResult& result) const override; ManagedDocumentResult& result) const override;
/// @brief lookup with callback, not thread-safe on same transaction::Context
bool readDocumentWithCallback(transaction::Methods* trx, LocalDocumentId const& token, bool readDocumentWithCallback(transaction::Methods* trx, LocalDocumentId const& token,
IndexIterator::DocumentCallback const& cb) const override; IndexIterator::DocumentCallback const& cb) const override;
Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
arangodb::ManagedDocumentResult& result, OperationOptions& options, arangodb::ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, KeyLockInfo* /*keyLockInfo*/,
TRI_voc_tick_t& revisionId, KeyLockInfo* /*keyLockInfo*/, std::function<void()> const& cbDuringLock) override;
std::function<Result(void)> const& callbackDuringLock) override;
Result update(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result update(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, ManagedDocumentResult& previousMdr) override;
ManagedDocumentResult& previous) override;
Result replace(transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result replace(transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& resultMdr, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previousMdr) override;
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) override;
Result remove(transaction::Methods& trx, velocypack::Slice slice, Result remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previous, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_rid_t& revisionId, KeyLockInfo* keyLockInfo, std::function<void()> const& cbDuringLock) override;
std::function<Result(void)> const& callbackDuringLock) override;
/// adjust the current number of docs /// adjust the current number of docs
void adjustNumberDocuments(TRI_voc_rid_t revisionId, int64_t adjustment); void adjustNumberDocuments(TRI_voc_rid_t revisionId, int64_t adjustment);
@ -209,18 +207,23 @@ class RocksDBCollection final : public PhysicalCollection {
arangodb::velocypack::Slice const& newDoc, arangodb::velocypack::Slice const& newDoc,
OperationOptions& options) const; OperationOptions& options) const;
arangodb::Result lookupDocumentVPack(LocalDocumentId const& documentId, /// @brief lookup document in cache and / or rocksdb
transaction::Methods*, /// @param readCache attempt to read from cache
arangodb::ManagedDocumentResult&, /// @param fillCache fill cache with found document
bool withCache) const; arangodb::Result lookupDocumentVPack(transaction::Methods* trx,
LocalDocumentId const& documentId,
rocksdb::PinnableSlice& ps,
bool readCache,
bool fillCache) const;
arangodb::Result lookupDocumentVPack(LocalDocumentId const& documentId, bool lookupDocumentVPack(transaction::Methods*,
transaction::Methods*, LocalDocumentId const& documentId,
IndexIterator::DocumentCallback const& cb, IndexIterator::DocumentCallback const& cb,
bool withCache) const; bool withCache) const;
/// @brief create hash-cache
void createCache() const; void createCache() const;
/// @brief destory hash-cache
void destroyCache() const; void destroyCache() const;
/// is this collection using a cache /// is this collection using a cache

View File

@ -44,6 +44,7 @@
#include "Transaction/Helpers.h" #include "Transaction/Helpers.h"
#include "Transaction/Methods.h" #include "Transaction/Methods.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/ManagedDocumentResult.h"
#include <rocksdb/db.h> #include <rocksdb/db.h>
#include <rocksdb/utilities/transaction_db.h> #include <rocksdb/utilities/transaction_db.h>
@ -895,6 +896,8 @@ void RocksDBEdgeIndex::warmupInternal(transaction::Methods* trx, rocksdb::Slice
std::unique_ptr<rocksdb::Iterator> it( std::unique_ptr<rocksdb::Iterator> it(
rocksutils::globalRocksDB()->NewIterator(options, _cf)); rocksutils::globalRocksDB()->NewIterator(options, _cf));
ManagedDocumentResult mdr;
size_t n = 0; size_t n = 0;
cache::Cache* cc = _cache.get(); cache::Cache* cc = _cache.get();
for (it->Seek(lower); it->Valid(); it->Next()) { for (it->Seek(lower); it->Valid(); it->Next()) {
@ -972,20 +975,19 @@ void RocksDBEdgeIndex::warmupInternal(transaction::Methods* trx, rocksdb::Slice
if (needsInsert) { if (needsInsert) {
LocalDocumentId const docId = LocalDocumentId const docId =
RocksDBKey::indexDocumentId(RocksDBEntryType::EdgeIndexValue, key); RocksDBKey::indexDocumentId(RocksDBEntryType::EdgeIndexValue, key);
if (!rocksColl->readDocumentWithCallback(trx, docId, [&](LocalDocumentId const&, VPackSlice doc) { if (!rocksColl->readDocument(trx, docId, mdr)) {
// Data Inconsistency. revision id without a document...
TRI_ASSERT(false);
continue;
}
builder.add(VPackValue(docId.id())); builder.add(VPackValue(docId.id()));
VPackSlice doc(mdr.vpack());
VPackSlice toFrom = VPackSlice toFrom =
_isFromIndex ? transaction::helpers::extractToFromDocument(doc) _isFromIndex ? transaction::helpers::extractToFromDocument(doc)
: transaction::helpers::extractFromFromDocument(doc); : transaction::helpers::extractFromFromDocument(doc);
TRI_ASSERT(toFrom.isString()); TRI_ASSERT(toFrom.isString());
builder.add(toFrom); builder.add(toFrom);
})) {
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
// Data Inconsistency.
// We have a revision id without a document...
TRI_ASSERT(false);
#endif
}
} }
} }

View File

@ -96,8 +96,6 @@ Result removeKeysOutsideRange(VPackSlice chunkSlice, LogicalCollection* coll,
VPackBuilder builder; VPackBuilder builder;
ManagedDocumentResult mdr; ManagedDocumentResult mdr;
TRI_voc_tick_t tick;
TRI_voc_rid_t prevRev, revisionId;
// remove everything from the beginning of the key range until the lowest // remove everything from the beginning of the key range until the lowest
// remote key // remote key
@ -108,8 +106,8 @@ Result removeKeysOutsideRange(VPackSlice chunkSlice, LogicalCollection* coll,
builder.clear(); builder.clear();
builder.add(velocypack::ValuePair(docKey.data(), docKey.size(), builder.add(velocypack::ValuePair(docKey.data(), docKey.size(),
velocypack::ValueType::String)); velocypack::ValueType::String));
auto r = physical->remove(trx, builder.slice(), mdr, options, tick, auto r = physical->remove(trx, builder.slice(), mdr, options,
false, prevRev, revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) { if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
// ignore not found, we remove conflicting docs ahead of time // ignore not found, we remove conflicting docs ahead of time
@ -145,8 +143,8 @@ Result removeKeysOutsideRange(VPackSlice chunkSlice, LogicalCollection* coll,
builder.clear(); builder.clear();
builder.add(velocypack::ValuePair(docKey.data(), docKey.size(), builder.add(velocypack::ValuePair(docKey.data(), docKey.size(),
velocypack::ValueType::String)); velocypack::ValueType::String));
auto r = physical->remove(trx, builder.slice(), mdr, options, tick, auto r = physical->remove(trx, builder.slice(), mdr, options,
false, prevRev, revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) { if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
// ignore not found, we remove conflicting docs ahead of time // ignore not found, we remove conflicting docs ahead of time
@ -252,8 +250,6 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
// state for RocksDBCollection insert/replace/remove // state for RocksDBCollection insert/replace/remove
ManagedDocumentResult mdr, previous; ManagedDocumentResult mdr, previous;
TRI_voc_tick_t resultTick;
TRI_voc_rid_t prevRev, revisionId;
transaction::BuilderLeaser keyBuilder(trx); transaction::BuilderLeaser keyBuilder(trx);
std::vector<size_t> toFetch; std::vector<size_t> toFetch;
@ -297,8 +293,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
keyBuilder->clear(); keyBuilder->clear();
keyBuilder->add(VPackValue(localKey)); keyBuilder->add(VPackValue(localKey));
auto r = physical->remove(*trx, keyBuilder->slice(), mdr, options, resultTick, auto r = physical->remove(*trx, keyBuilder->slice(), mdr, options,
false, prevRev, revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) { if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
// ignore not found, we remove conflicting docs ahead of time // ignore not found, we remove conflicting docs ahead of time
@ -351,8 +347,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
keyBuilder->clear(); keyBuilder->clear();
keyBuilder->add(VPackValue(localKey)); keyBuilder->add(VPackValue(localKey));
auto r = physical->remove(*trx, keyBuilder->slice(), mdr, options, resultTick, auto r = physical->remove(*trx, keyBuilder->slice(), mdr, options,
false, prevRev, revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) { if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
// ignore not found, we remove conflicting docs ahead of time // ignore not found, we remove conflicting docs ahead of time
@ -476,8 +472,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
keyBuilder->clear(); keyBuilder->clear();
keyBuilder->add(VPackValue(conflictingKey)); keyBuilder->add(VPackValue(conflictingKey));
auto res = physical->remove(*trx, keyBuilder->slice(), mdr, options, resultTick, auto res = physical->remove(*trx, keyBuilder->slice(), mdr, options,
false, prevRev, revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (res.ok()) { if (res.ok()) {
++stats.numDocsRemoved; ++stats.numDocsRemoved;
@ -492,8 +488,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
// INSERT // INSERT
TRI_ASSERT(options.indexOperationMode == Index::OperationMode::internal); TRI_ASSERT(options.indexOperationMode == Index::OperationMode::internal);
Result res = physical->insert(trx, it, mdr, options, resultTick, false, Result res = physical->insert(trx, it, mdr, options,
revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (res.fail()) { if (res.fail()) {
if (res.is(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED) && if (res.is(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED) &&
res.errorMessage() > keySlice.copyString()) { res.errorMessage() > keySlice.copyString()) {
@ -504,8 +500,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
return res; return res;
} }
res = physical->insert(trx, it, mdr, options, resultTick, false, res = physical->insert(trx, it, mdr, options,
revisionId, nullptr, nullptr); /*lock*/false, nullptr, nullptr);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
@ -520,8 +516,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
// REPLACE // REPLACE
TRI_ASSERT(options.indexOperationMode == Index::OperationMode::internal); TRI_ASSERT(options.indexOperationMode == Index::OperationMode::internal);
Result res = physical->replace(trx, it, mdr, options, resultTick, false, Result res = physical->replace(trx, it, mdr, options,
prevRev, previous); /*lock*/false, previous);
if (res.fail()) { if (res.fail()) {
if (res.is(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED) && if (res.is(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED) &&
res.errorMessage() > keySlice.copyString()) { res.errorMessage() > keySlice.copyString()) {
@ -531,8 +527,8 @@ Result syncChunkRocksDB(DatabaseInitialSyncer& syncer, SingleCollectionTransacti
if (inner.fail()) { if (inner.fail()) {
return res; return res;
} }
res = physical->replace(trx, it, mdr, options, resultTick, false, res = physical->replace(trx, it, mdr, options,
prevRev, previous); /*lock*/false, previous);
if (res.fail()) { if (res.fail()) {
return res; return res;
} }
@ -735,11 +731,8 @@ Result handleSyncKeysRocksDB(DatabaseInitialSyncer& syncer,
tempBuilder.add(VPackValue(docKey)); tempBuilder.add(VPackValue(docKey));
ManagedDocumentResult previous; ManagedDocumentResult previous;
TRI_voc_rid_t resultMarkerTick;
TRI_voc_rid_t prevRev, revisionId;
auto r = physical->remove(trx, tempBuilder.slice(), previous, auto r = physical->remove(trx, tempBuilder.slice(), previous,
options, resultMarkerTick, false, prevRev, options, /*lock*/false, nullptr, nullptr);
revisionId, nullptr, nullptr);
if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) { if (r.fail() && r.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
// ignore not found, we remove conflicting docs ahead of time // ignore not found, we remove conflicting docs ahead of time

View File

@ -76,7 +76,8 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
void toVelocyPack(VPackBuilder&, std::underlying_type<Index::Serialize>::type) const override; void toVelocyPack(VPackBuilder&, std::underlying_type<Index::Serialize>::type) const override;
LocalDocumentId lookupKey(transaction::Methods* trx, arangodb::velocypack::StringRef key) const; LocalDocumentId lookupKey(transaction::Methods* trx,
arangodb::velocypack::StringRef key) const;
/// @brief reads a revision id from the primary index /// @brief reads a revision id from the primary index
/// if the document does not exist, this function will return false /// if the document does not exist, this function will return false

View File

@ -111,12 +111,12 @@ class RocksDBVPackUniqueIndexIterator final : public IndexIterator {
_done = true; _done = true;
rocksdb::PinnableSlice val; rocksdb::PinnableSlice ps;
RocksDBMethods* mthds = RocksDBTransactionState::toMethods(_trx); RocksDBMethods* mthds = RocksDBTransactionState::toMethods(_trx);
rocksdb::Status s = mthds->Get(_index->columnFamily(), _key->string(), &val); rocksdb::Status s = mthds->Get(_index->columnFamily(), _key->string(), &ps);
if (s.ok()) { if (s.ok()) {
cb(RocksDBValue::documentId(val)); cb(RocksDBValue::documentId(ps));
} }
// there is at most one element, so we are done now // there is at most one element, so we are done now
@ -133,12 +133,12 @@ class RocksDBVPackUniqueIndexIterator final : public IndexIterator {
_done = true; _done = true;
rocksdb::PinnableSlice val; rocksdb::PinnableSlice ps;
RocksDBMethods* mthds = RocksDBTransactionState::toMethods(_trx); RocksDBMethods* mthds = RocksDBTransactionState::toMethods(_trx);
rocksdb::Status s = mthds->Get(_index->columnFamily(), _key->string(), &val); rocksdb::Status s = mthds->Get(_index->columnFamily(), _key->string(), &ps);
if (s.ok()) { if (s.ok()) {
cb(LocalDocumentId(RocksDBValue::documentId(val)), cb(LocalDocumentId(RocksDBValue::documentId(ps)),
RocksDBKey::indexedVPack(_key.ref())); RocksDBKey::indexedVPack(_key.ref()));
} }

View File

@ -156,48 +156,47 @@ class PhysicalCollection {
virtual Result read(transaction::Methods*, arangodb::velocypack::Slice const& key, virtual Result read(transaction::Methods*, arangodb::velocypack::Slice const& key,
ManagedDocumentResult& result, bool lock) = 0; ManagedDocumentResult& result, bool lock) = 0;
/// @brief read a documument referenced by token (internal method)
virtual bool readDocument(transaction::Methods* trx, LocalDocumentId const& token, virtual bool readDocument(transaction::Methods* trx, LocalDocumentId const& token,
ManagedDocumentResult& result) const = 0; ManagedDocumentResult& result) const = 0;
/// @brief read a documument referenced by token (internal method)
virtual bool readDocumentWithCallback(transaction::Methods* trx, virtual bool readDocumentWithCallback(transaction::Methods* trx,
LocalDocumentId const& token, LocalDocumentId const& token,
IndexIterator::DocumentCallback const& cb) const = 0; IndexIterator::DocumentCallback const& cb) const = 0;
/** /**
* @param callbackDuringLock Called immediately after a successful insert. If * @brief Perform document insert, may generate a '_key' value
* it returns a failure, the insert will be rolled back. If the insert wasn't * If (options.returnNew == false && !options.silent) result might
* successful, it isn't called. May be nullptr. * just contain an object with the '_key' field
* @param callbackDuringLock Called immediately after a successful insert.
* If the insert wasn't successful, it isn't called. May be nullptr.
*/ */
virtual Result insert(arangodb::transaction::Methods* trx, virtual Result insert(arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice newSlice, arangodb::velocypack::Slice newSlice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& result,
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, OperationOptions& options,
bool lock, TRI_voc_tick_t& revisionId, KeyLockInfo* keyLockInfo, bool lock, KeyLockInfo* keyLockInfo,
std::function<Result(void)> const& callbackDuringLock) = 0; std::function<void()> const& cbDuringLock) = 0;
Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice, Result insert(arangodb::transaction::Methods* trx, arangodb::velocypack::Slice newSlice,
arangodb::ManagedDocumentResult& result, OperationOptions& options, arangodb::ManagedDocumentResult& result, OperationOptions& options, bool lock) {
TRI_voc_tick_t& resultMarkerTick, bool lock) { return insert(trx, newSlice, result, options, lock, nullptr, nullptr);
TRI_voc_rid_t unused;
return insert(trx, newSlice, result, options, resultMarkerTick, lock,
unused, nullptr, nullptr);
} }
virtual Result update(arangodb::transaction::Methods* trx, virtual Result update(arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice newSlice, arangodb::velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previous) = 0;
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) = 0;
virtual Result replace(transaction::Methods* trx, arangodb::velocypack::Slice newSlice, virtual Result replace(arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previous) = 0;
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) = 0;
virtual Result remove(transaction::Methods& trx, velocypack::Slice slice, virtual Result remove(transaction::Methods& trx, velocypack::Slice slice,
ManagedDocumentResult& previous, OperationOptions& options, ManagedDocumentResult& previous, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_rid_t& revisionId, KeyLockInfo* keyLockInfo, std::function<void()> const& cbDuringLock) = 0;
std::function<Result(void)> const& callbackDuringLock) = 0;
protected: protected:
PhysicalCollection(LogicalCollection& collection, arangodb::velocypack::Slice const& info); PhysicalCollection(LogicalCollection& collection, arangodb::velocypack::Slice const& info);

View File

@ -69,6 +69,7 @@ transaction::Context::Context(TRI_vocbase_t& vocbase)
_customTypeHandler(), _customTypeHandler(),
_builders{_arena}, _builders{_arena},
_stringBuffer(), _stringBuffer(),
_strings{_strArena},
_options(arangodb::velocypack::Options::Defaults), _options(arangodb::velocypack::Options::Defaults),
_dumpOptions(arangodb::velocypack::Options::Defaults), _dumpOptions(arangodb::velocypack::Options::Defaults),
_transaction{0, false}, _transaction{0, false},
@ -143,17 +144,26 @@ void transaction::Context::returnStringBuffer(basics::StringBuffer* stringBuffer
/// @brief temporarily lease a std::string /// @brief temporarily lease a std::string
std::string* transaction::Context::leaseString() { std::string* transaction::Context::leaseString() {
if (_stdString == nullptr) { if (_strings.empty()) {
_stdString.reset(new std::string()); // create a new string and return it
} else { return new std::string();
_stdString->clear();
} }
return _stdString.release();
// re-use an existing string
std::string* s = _strings.back();
s->clear();
_strings.pop_back();
return s;
} }
/// @brief return a temporary std::string object /// @brief return a temporary std::string object
void transaction::Context::returnString(std::string* str) { void transaction::Context::returnString(std::string* str) {
_stdString.reset(str); try { // put string back into our vector of strings
_strings.push_back(str);
} catch (...) {
// no harm done. just wipe the string
delete str;
}
} }
/// @brief temporarily lease a Builder object /// @brief temporarily lease a Builder object

View File

@ -143,13 +143,13 @@ class Context {
SmallVector<arangodb::velocypack::Builder*, 32> _builders; SmallVector<arangodb::velocypack::Builder*, 32> _builders;
std::unique_ptr<arangodb::basics::StringBuffer> _stringBuffer; std::unique_ptr<arangodb::basics::StringBuffer> _stringBuffer;
std::unique_ptr<std::string> _stdString;
SmallVector<std::string*, 32>::allocator_type::arena_type _strArena;
SmallVector<std::string*, 32> _strings;
arangodb::velocypack::Options _options; arangodb::velocypack::Options _options;
arangodb::velocypack::Options _dumpOptions; arangodb::velocypack::Options _dumpOptions;
private:
private: private:
std::unique_ptr<transaction::ContextData> _contextData; std::unique_ptr<transaction::ContextData> _contextData;

View File

@ -1748,16 +1748,14 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN
std::shared_ptr<std::vector<ServerID> const> followers; std::shared_ptr<std::vector<ServerID> const> followers;
std::function<Result(void)> updateFollowers = nullptr; std::function<void()> updateFollowers;
if (needsToGetFollowersUnderLock) { if (needsToGetFollowersUnderLock) {
FollowerInfo const& followerInfo = *collection->followers(); FollowerInfo const& followerInfo = *collection->followers();
updateFollowers = [&followerInfo, &followers]() -> Result { updateFollowers = [&followerInfo, &followers]() {
TRI_ASSERT(followers == nullptr); TRI_ASSERT(followers == nullptr);
followers = followerInfo.get(); followers = followerInfo.get();
return Result{};
}; };
} else if (_state->isDBServer()) { } else if (_state->isDBServer()) {
TRI_ASSERT(followers == nullptr); TRI_ASSERT(followers == nullptr);
@ -1808,8 +1806,8 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN
} }
VPackBuilder resultBuilder; VPackBuilder resultBuilder;
ManagedDocumentResult documentResult; ManagedDocumentResult docResult;
TRI_voc_tick_t maxTick = 0; ManagedDocumentResult prevDocResult; // return OLD (with override option)
auto workForOneDocument = [&](VPackSlice const value) -> Result { auto workForOneDocument = [&](VPackSlice const value) -> Result {
if (!value.isObject()) { if (!value.isObject()) {
@ -1822,9 +1820,8 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN
return Result(r); return Result(r);
} }
TRI_voc_tick_t resultMarkerTick = 0; docResult.clear();
TRI_voc_rid_t revisionId = 0; prevDocResult.clear();
documentResult.clear();
// insert with overwrite may NOT be a single document operation, as we // insert with overwrite may NOT be a single document operation, as we
// possibly need to do two separate operations (insert and replace). // possibly need to do two separate operations (insert and replace).
@ -1832,34 +1829,21 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN
TRI_ASSERT(needsLock == !isLocked(collection, AccessMode::Type::WRITE)); TRI_ASSERT(needsLock == !isLocked(collection, AccessMode::Type::WRITE));
Result res = Result res =
collection->insert(this, value, documentResult, options, resultMarkerTick, collection->insert(this, value, docResult, options,
needsLock, revisionId, &keyLockInfo, updateFollowers); needsLock, &keyLockInfo, updateFollowers);
TRI_voc_rid_t previousRevisionId = 0;
ManagedDocumentResult previousDocumentResult; // return OLD
bool didReplace = false;
if (options.overwrite && res.is(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED)) { if (options.overwrite && res.is(TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED)) {
// RepSert Case - unique_constraint violated -> maxTick has not changed -> // RepSert Case - unique_constraint violated -> try replace
// try replace
resultMarkerTick = 0;
// If we're overwriting, we already have a lock. Therefore we also don't // If we're overwriting, we already have a lock. Therefore we also don't
// need to get the followers under the lock. // need to get the followers under the lock.
TRI_ASSERT(!needsLock); TRI_ASSERT(!needsLock);
TRI_ASSERT(!needsToGetFollowersUnderLock); TRI_ASSERT(!needsToGetFollowersUnderLock);
TRI_ASSERT(updateFollowers == nullptr); TRI_ASSERT(updateFollowers == nullptr);
res = collection->replace(this, value, documentResult, options, res = collection->replace(this, value, docResult, options,
resultMarkerTick, false, previousRevisionId, /*lock*/false, prevDocResult);
previousDocumentResult); TRI_ASSERT(res.fail() || prevDocResult.revisionId() != 0);
if (res.ok() && !options.silent) { didReplace = true;
// If we are silent, then revisionId will not be looked at further
// down. In the silent case, documentResult is empty, so nobody
// must actually look at it!
revisionId = TRI_ExtractRevisionId(VPackSlice(documentResult.vpack()));
}
}
if (resultMarkerTick > 0 && resultMarkerTick > maxTick) {
maxTick = resultMarkerTick;
} }
if (res.fail()) { if (res.fail()) {
@ -1869,21 +1853,22 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN
} }
if (!options.silent) { if (!options.silent) {
TRI_ASSERT(!documentResult.empty()); const bool showReplaced = (options.returnOld && didReplace);
TRI_ASSERT(!options.returnNew || !docResult.empty());
TRI_ASSERT(!showReplaced || !prevDocResult.empty());
arangodb::velocypack::StringRef keyString(transaction::helpers::extractKeyFromDocument( arangodb::velocypack::StringRef keyString;
VPackSlice(documentResult.vpack()))); if (didReplace) { // docResult may be empty, but replace requires '_key' in value
keyString = value.get(StaticStrings::KeyString);
bool showReplaced = false; TRI_ASSERT(!keyString.empty());
if (options.returnOld && previousRevisionId) { } else {
showReplaced = true; keyString = transaction::helpers::extractKeyFromDocument(VPackSlice(docResult.vpack()));
TRI_ASSERT(!previousDocumentResult.empty());
} }
buildDocumentIdentity(collection, resultBuilder, cid, keyString, buildDocumentIdentity(collection, resultBuilder, cid, keyString,
revisionId, previousRevisionId, docResult.revisionId(), prevDocResult.revisionId(),
showReplaced ? &previousDocumentResult : nullptr, showReplaced ? &prevDocResult : nullptr,
options.returnNew ? &documentResult : nullptr); options.returnNew ? &docResult : nullptr);
} }
return Result(); return Result();
}; };
@ -1921,11 +1906,6 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN
} }
} }
// wait for operation(s) to be synced to disk here. On rocksdb maxTick == 0
if (res.ok() && options.waitForSync && maxTick > 0 && isSingleOperationTransaction()) {
EngineSelectorFeature::ENGINE->waitForSyncTick(maxTick);
}
if (options.silent) { if (options.silent) {
// We needed the results, but do not want to report: // We needed the results, but do not want to report:
resultBuilder.clear(); resultBuilder.clear();
@ -2130,12 +2110,11 @@ OperationResult transaction::Methods::modifyLocal(std::string const& collectionN
TRI_ASSERT(needsLock == lockResult.is(TRI_ERROR_LOCKED)); TRI_ASSERT(needsLock == lockResult.is(TRI_ERROR_LOCKED));
VPackBuilder resultBuilder; // building the complete result VPackBuilder resultBuilder; // building the complete result
TRI_voc_tick_t maxTick = 0;
ManagedDocumentResult previous; ManagedDocumentResult previous;
ManagedDocumentResult result; ManagedDocumentResult result;
// lambda ////////////// // lambda //////////////
auto workForOneDocument = [this, &operation, &options, &maxTick, &collection, auto workForOneDocument = [this, &operation, &options, &collection,
&resultBuilder, &cid, &previous, &resultBuilder, &cid, &previous,
&result](VPackSlice const newVal, bool isBabies) -> Result { &result](VPackSlice const newVal, bool isBabies) -> Result {
Result res; Result res;
@ -2144,8 +2123,6 @@ OperationResult transaction::Methods::modifyLocal(std::string const& collectionN
return res; return res;
} }
TRI_voc_rid_t actualRevision = 0;
TRI_voc_tick_t resultMarkerTick = 0;
result.clear(); result.clear();
previous.clear(); previous.clear();
@ -2154,33 +2131,32 @@ OperationResult transaction::Methods::modifyLocal(std::string const& collectionN
TRI_ASSERT(isLocked(collection, AccessMode::Type::WRITE)); TRI_ASSERT(isLocked(collection, AccessMode::Type::WRITE));
if (operation == TRI_VOC_DOCUMENT_OPERATION_REPLACE) { if (operation == TRI_VOC_DOCUMENT_OPERATION_REPLACE) {
res = collection->replace(this, newVal, result, options, resultMarkerTick, res = collection->replace(this, newVal, result, options,
false, actualRevision, previous); /*lock*/false, previous);
} else { } else {
res = collection->update(this, newVal, result, options, resultMarkerTick, res = collection->update(this, newVal, result, options,
false, actualRevision, previous); /*lock*/false, previous);
}
if (resultMarkerTick > 0 && resultMarkerTick > maxTick) {
maxTick = resultMarkerTick;
} }
if (res.fail()) { if (res.fail()) {
if (res.is(TRI_ERROR_ARANGO_CONFLICT) && !isBabies) { if (res.is(TRI_ERROR_ARANGO_CONFLICT) && !isBabies) {
TRI_ASSERT(previous.revisionId() != 0);
arangodb::velocypack::StringRef key(newVal.get(StaticStrings::KeyString)); arangodb::velocypack::StringRef key(newVal.get(StaticStrings::KeyString));
buildDocumentIdentity(collection, resultBuilder, cid, key, actualRevision, buildDocumentIdentity(collection, resultBuilder, cid, key, previous.revisionId(),
0, options.returnOld ? &previous : nullptr, nullptr); 0, options.returnOld ? &previous : nullptr, nullptr);
} }
return res; return res;
} }
if (!options.silent) { if (!options.silent) {
TRI_ASSERT(!previous.empty()); TRI_ASSERT(!options.returnOld || !previous.empty());
TRI_ASSERT(!result.empty()); TRI_ASSERT(!options.returnNew || !result.empty());
TRI_ASSERT(result.revisionId() != 0 && previous.revisionId() != 0);
arangodb::velocypack::StringRef key(newVal.get(StaticStrings::KeyString)); arangodb::velocypack::StringRef key(newVal.get(StaticStrings::KeyString));
buildDocumentIdentity(collection, resultBuilder, cid, key, buildDocumentIdentity(collection, resultBuilder, cid, key,
TRI_ExtractRevisionId(VPackSlice(result.vpack())), result.revisionId(), previous.revisionId(),
actualRevision, options.returnOld ? &previous : nullptr, options.returnOld ? &previous : nullptr,
options.returnNew ? &result : nullptr); options.returnNew ? &result : nullptr);
} }
@ -2234,11 +2210,6 @@ OperationResult transaction::Methods::modifyLocal(std::string const& collectionN
} }
} }
// wait for operation(s) to be synced to disk here. On rocksdb maxTick == 0
if (res.ok() && options.waitForSync && maxTick > 0 && isSingleOperationTransaction()) {
EngineSelectorFeature::ENGINE->waitForSyncTick(maxTick);
}
if (options.silent) { if (options.silent) {
// We needed the results, but do not want to report: // We needed the results, but do not want to report:
resultBuilder.clear(); resultBuilder.clear();
@ -2338,16 +2309,14 @@ OperationResult transaction::Methods::removeLocal(std::string const& collectionN
std::shared_ptr<std::vector<ServerID> const> followers; std::shared_ptr<std::vector<ServerID> const> followers;
std::function<Result(void)> updateFollowers = nullptr; std::function<void()> updateFollowers = nullptr;
if (needsToGetFollowersUnderLock) { if (needsToGetFollowersUnderLock) {
auto const& followerInfo = *collection->followers(); auto const& followerInfo = *collection->followers();
updateFollowers = [&followerInfo, &followers]() -> Result { updateFollowers = [&followerInfo, &followers]() {
TRI_ASSERT(followers == nullptr); TRI_ASSERT(followers == nullptr);
followers = followerInfo.get(); followers = followerInfo.get();
return Result{};
}; };
} else if (_state->isDBServer()) { } else if (_state->isDBServer()) {
TRI_ASSERT(followers == nullptr); TRI_ASSERT(followers == nullptr);
@ -2399,10 +2368,8 @@ OperationResult transaction::Methods::removeLocal(std::string const& collectionN
VPackBuilder resultBuilder; VPackBuilder resultBuilder;
ManagedDocumentResult previous; ManagedDocumentResult previous;
TRI_voc_tick_t maxTick = 0;
auto workForOneDocument = [&](VPackSlice value, bool isBabies) -> Result { auto workForOneDocument = [&](VPackSlice value, bool isBabies) -> Result {
TRI_voc_rid_t actualRevision = 0;
transaction::BuilderLeaser builder(this); transaction::BuilderLeaser builder(this);
arangodb::velocypack::StringRef key; arangodb::velocypack::StringRef key;
if (value.isString()) { if (value.isString()) {
@ -2423,33 +2390,30 @@ OperationResult transaction::Methods::removeLocal(std::string const& collectionN
return Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); return Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
} }
TRI_voc_tick_t resultMarkerTick = 0;
previous.clear(); previous.clear();
TRI_ASSERT(needsLock == !isLocked(collection, AccessMode::Type::WRITE)); TRI_ASSERT(needsLock == !isLocked(collection, AccessMode::Type::WRITE));
auto res = collection->remove(*this, value, options, resultMarkerTick, needsLock, auto res = collection->remove(*this, value, options, needsLock,
actualRevision, previous, &keyLockInfo, updateFollowers); previous, &keyLockInfo, updateFollowers);
if (resultMarkerTick > 0 && resultMarkerTick > maxTick) {
maxTick = resultMarkerTick;
}
if (res.fail()) { if (res.fail()) {
if (res.is(TRI_ERROR_ARANGO_CONFLICT) && !isBabies) { if (res.is(TRI_ERROR_ARANGO_CONFLICT) && !isBabies) {
buildDocumentIdentity(collection, resultBuilder, cid, key, actualRevision, TRI_ASSERT(previous.revisionId() != 0);
buildDocumentIdentity(collection, resultBuilder, cid, key, previous.revisionId(),
0, options.returnOld ? &previous : nullptr, nullptr); 0, options.returnOld ? &previous : nullptr, nullptr);
} }
return res; return res;
} }
TRI_ASSERT(!previous.empty());
if (!options.silent) { if (!options.silent) {
buildDocumentIdentity(collection, resultBuilder, cid, key, actualRevision, TRI_ASSERT(!options.returnOld || !previous.empty());
TRI_ASSERT(previous.revisionId() != 0);
buildDocumentIdentity(collection, resultBuilder, cid, key, previous.revisionId(),
0, options.returnOld ? &previous : nullptr, nullptr); 0, options.returnOld ? &previous : nullptr, nullptr);
} }
return Result(); return res;
}; };
Result res; Result res;
@ -2486,11 +2450,6 @@ OperationResult transaction::Methods::removeLocal(std::string const& collectionN
} }
} }
// wait for operation(s) to be synced to disk here. On rocksdb maxTick == 0
if (res.ok() && options.waitForSync && maxTick > 0 && isSingleOperationTransaction()) {
EngineSelectorFeature::ENGINE->waitForSyncTick(maxTick);
}
if (options.silent) { if (options.silent) {
// We needed the results, but do not want to report: // We needed the results, but do not want to report:
resultBuilder.clear(); resultBuilder.clear();
@ -3365,7 +3324,7 @@ Result Methods::replicateOperations(LogicalCollection const& collection,
std::shared_ptr<const std::vector<std::string>> const& followers, std::shared_ptr<const std::vector<std::string>> const& followers,
OperationOptions const& options, VPackSlice const value, OperationOptions const& options, VPackSlice const value,
TRI_voc_document_operation_e const operation, TRI_voc_document_operation_e const operation,
VPackBuilder& resultBuilder) { VPackBuilder const& resultBuilder) {
TRI_ASSERT(followers != nullptr); TRI_ASSERT(followers != nullptr);
Result res; Result res;

View File

@ -501,13 +501,6 @@ class Methods {
ENTERPRISE_VIRT Result unlockRecursive(TRI_voc_cid_t, AccessMode::Type); ENTERPRISE_VIRT Result unlockRecursive(TRI_voc_cid_t, AccessMode::Type);
private: private:
/// @brief replicates operations from leader to follower(s)
Result replicateOperations(LogicalCollection* collection,
arangodb::velocypack::Slice const& inputValue,
arangodb::velocypack::Builder const& resultBuilder,
std::shared_ptr<std::vector<std::string> const>& followers,
arangodb::rest::RequestType requestType,
std::string const& pathAppendix);
/// @brief Helper create a Cluster Communication document /// @brief Helper create a Cluster Communication document
OperationResult clusterResultDocument(rest::ResponseCode const& responseCode, OperationResult clusterResultDocument(rest::ResponseCode const& responseCode,
@ -583,7 +576,7 @@ class Methods {
std::shared_ptr<const std::vector<std::string>> const& followers, std::shared_ptr<const std::vector<std::string>> const& followers,
OperationOptions const& options, VPackSlice value, OperationOptions const& options, VPackSlice value,
TRI_voc_document_operation_e operation, TRI_voc_document_operation_e operation,
VPackBuilder& resultBuilder); VPackBuilder const& resultBuilder);
}; };
} // namespace transaction } // namespace transaction

View File

@ -940,68 +940,56 @@ Result LogicalCollection::compact() {
Result LogicalCollection::insert(transaction::Methods* trx, VPackSlice const slice, Result LogicalCollection::insert(transaction::Methods* trx, VPackSlice const slice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, KeyLockInfo* keyLockInfo,
TRI_voc_rid_t& revisionId, KeyLockInfo* keyLockInfo, std::function<void()> const& cbDuringLock) {
std::function<Result(void)> callbackDuringLock) {
TRI_IF_FAILURE("LogicalCollection::insert") { TRI_IF_FAILURE("LogicalCollection::insert") {
return Result(TRI_ERROR_DEBUG); return Result(TRI_ERROR_DEBUG);
} }
resultMarkerTick = 0; return getPhysical()->insert(trx, slice, result, options, lock,
return getPhysical()->insert(trx, slice, result, options, resultMarkerTick, lock, keyLockInfo, cbDuringLock);
revisionId, keyLockInfo, std::move(callbackDuringLock));
} }
/// @brief updates a document or edge in a collection /// @brief updates a document or edge in a collection
Result LogicalCollection::update(transaction::Methods* trx, VPackSlice const newSlice, Result LogicalCollection::update(transaction::Methods* trx, VPackSlice const newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previous) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
TRI_IF_FAILURE("LogicalCollection::update") { TRI_IF_FAILURE("LogicalCollection::update") {
return Result(TRI_ERROR_DEBUG); return Result(TRI_ERROR_DEBUG);
} }
resultMarkerTick = 0;
if (!newSlice.isObject()) { if (!newSlice.isObject()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID); return Result(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
} }
prevRev = 0; return getPhysical()->update(trx, newSlice, result, options, lock,
return getPhysical()->update(trx, newSlice, result, options, resultMarkerTick, lock, previous);
prevRev, previous);
} }
/// @brief replaces a document or edge in a collection /// @brief replaces a document or edge in a collection
Result LogicalCollection::replace(transaction::Methods* trx, VPackSlice const newSlice, Result LogicalCollection::replace(transaction::Methods* trx, VPackSlice const newSlice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, bool lock, ManagedDocumentResult& previous) {
TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous) {
TRI_IF_FAILURE("LogicalCollection::replace") { TRI_IF_FAILURE("LogicalCollection::replace") {
return Result(TRI_ERROR_DEBUG); return Result(TRI_ERROR_DEBUG);
} }
resultMarkerTick = 0;
if (!newSlice.isObject()) { if (!newSlice.isObject()) {
return Result(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID); return Result(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
} }
prevRev = 0; return getPhysical()->replace(trx, newSlice, result, options, lock,
return getPhysical()->replace(trx, newSlice, result, options, resultMarkerTick, lock, previous);
prevRev, previous);
} }
/// @brief removes a document or edge /// @brief removes a document or edge
Result LogicalCollection::remove(transaction::Methods& trx, velocypack::Slice const slice, Result LogicalCollection::remove(transaction::Methods& trx, velocypack::Slice const slice,
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, OperationOptions& options, bool lock,
bool lock, TRI_voc_rid_t& prevRev,
ManagedDocumentResult& previous, KeyLockInfo* keyLockInfo, ManagedDocumentResult& previous, KeyLockInfo* keyLockInfo,
std::function<Result(void)> callbackDuringLock) { std::function<void()> const& cbDuringLock) {
TRI_IF_FAILURE("LogicalCollection::remove") { TRI_IF_FAILURE("LogicalCollection::remove") {
return Result(TRI_ERROR_DEBUG); return Result(TRI_ERROR_DEBUG);
} }
resultMarkerTick = 0; return getPhysical()->remove(trx, slice, previous, options,
TRI_voc_rid_t revisionId = 0; lock, keyLockInfo, cbDuringLock);
return getPhysical()->remove(trx, slice, previous, options, resultMarkerTick,
lock, prevRev, revisionId, keyLockInfo,
std::move(callbackDuringLock));
} }
bool LogicalCollection::readDocument(transaction::Methods* trx, LocalDocumentId const& token, bool LogicalCollection::readDocument(transaction::Methods* trx, LocalDocumentId const& token,

View File

@ -297,34 +297,31 @@ class LogicalCollection : public LogicalDataSource {
// convenience function for downwards-compatibility // convenience function for downwards-compatibility
Result insert(transaction::Methods* trx, velocypack::Slice const slice, Result insert(transaction::Methods* trx, velocypack::Slice const slice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock) { bool lock) {
TRI_voc_rid_t unused; return insert(trx, slice, result, options, lock, nullptr, nullptr);
return insert(trx, slice, result, options, resultMarkerTick, lock, unused,
nullptr, nullptr);
} }
/** /**
* @param callbackDuringLock Called immediately after a successful insert. If * @param cbDuringLock Called immediately after a successful insert. If
* it returns a failure, the insert will be rolled back. If the insert wasn't * it returns a failure, the insert will be rolled back. If the insert wasn't
* successful, it isn't called. May be nullptr. * successful, it isn't called. May be nullptr.
*/ */
Result insert(transaction::Methods* trx, velocypack::Slice slice, Result insert(transaction::Methods* trx, velocypack::Slice slice,
ManagedDocumentResult& result, OperationOptions& options, ManagedDocumentResult& result, OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& revisionId, bool lock, KeyLockInfo* keyLockInfo, std::function<void()> const& cbDuringLock);
KeyLockInfo* keyLockInfo, std::function<Result(void)> callbackDuringLock);
Result update(transaction::Methods*, velocypack::Slice, Result update(transaction::Methods*, velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions&, TRI_voc_tick_t&, ManagedDocumentResult& result, OperationOptions&,
bool lock, TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous); bool lock, ManagedDocumentResult& previousMdr);
Result replace(transaction::Methods*, velocypack::Slice, Result replace(transaction::Methods*, velocypack::Slice newSlice,
ManagedDocumentResult& result, OperationOptions&, TRI_voc_tick_t&, ManagedDocumentResult& result, OperationOptions&,
bool lock, TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous); bool lock, ManagedDocumentResult& previousMdr);
Result remove(transaction::Methods& trx, velocypack::Slice slice, Result remove(transaction::Methods& trx, velocypack::Slice slice,
OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, OperationOptions& options,
bool lock, TRI_voc_rid_t& prevRev, ManagedDocumentResult& previous, bool lock, ManagedDocumentResult& previousMdr,
KeyLockInfo* keyLockInfo, std::function<Result(void)> callbackDuringLock); KeyLockInfo* keyLockInfo, std::function<void()> const& cbDuringLock);
bool readDocument(transaction::Methods* trx, LocalDocumentId const& token, bool readDocument(transaction::Methods* trx, LocalDocumentId const& token,
ManagedDocumentResult& result) const; ManagedDocumentResult& result) const;

View File

@ -23,6 +23,7 @@
#include "ManagedDocumentResult.h" #include "ManagedDocumentResult.h"
#include "Aql/AqlValue.h" #include "Aql/AqlValue.h"
#include "Transaction/Helpers.h"
#include <velocypack/Builder.h> #include <velocypack/Builder.h>
#include <velocypack/Slice.h> #include <velocypack/Slice.h>
@ -30,35 +31,35 @@
using namespace arangodb; using namespace arangodb;
void ManagedDocumentResult::setUnmanaged(uint8_t const* vpack, void ManagedDocumentResult::setUnmanaged(uint8_t const* vpack) {
LocalDocumentId const& documentId) {
_string.clear(); _string.clear();
_vpack = const_cast<uint8_t*>(vpack); _vpack = const_cast<uint8_t*>(vpack);
_localDocumentId = documentId; _revisionId = transaction::helpers::extractRevFromDocument(VPackSlice(vpack));
_managed = false;
} }
void ManagedDocumentResult::setManaged(uint8_t const* vpack, LocalDocumentId const& documentId) { void ManagedDocumentResult::setManaged(uint8_t const* vpack) {
_string.assign(reinterpret_cast<char const*>(vpack), VPackSlice(vpack).byteSize()); VPackSlice const slice(vpack);
_string.assign(slice.startAs<char>(), slice.byteSize());
_vpack = nullptr; _vpack = nullptr;
_localDocumentId = documentId; _revisionId = transaction::helpers::extractRevFromDocument(slice);
_managed = true; }
void ManagedDocumentResult::setRevisionId() noexcept {
TRI_ASSERT(!this->empty());
_revisionId = transaction::helpers::extractRevFromDocument(VPackSlice(this->vpack()));
} }
void ManagedDocumentResult::addToBuilder(velocypack::Builder& builder, void ManagedDocumentResult::addToBuilder(velocypack::Builder& builder,
bool allowExternals) const { bool allowExternals) const {
uint8_t const* vpack; TRI_ASSERT(!empty());
if (_managed) { if (_vpack == nullptr) { // managed
vpack = reinterpret_cast<uint8_t const*>(_string.data()); TRI_ASSERT(!_string.empty());
builder.add(VPackSlice(_string.data()));
} else { } else {
vpack = _vpack; if (allowExternals) {
builder.addExternal(_vpack);
} else {
builder.add(VPackSlice(_vpack));
} }
TRI_ASSERT(vpack != nullptr);
auto slice = velocypack::Slice(vpack);
TRI_ASSERT(!slice.isExternal());
if (allowExternals && canUseInExternal()) {
builder.addExternal(slice.begin());
} else {
builder.add(slice);
} }
} }

View File

@ -35,7 +35,7 @@ class Builder;
class ManagedDocumentResult { class ManagedDocumentResult {
public: public:
ManagedDocumentResult() : _vpack(nullptr), _managed(false) {} ManagedDocumentResult() : _vpack(nullptr), _revisionId(0) {}
ManagedDocumentResult(ManagedDocumentResult const& other) = default; ManagedDocumentResult(ManagedDocumentResult const& other) = default;
ManagedDocumentResult& operator=(ManagedDocumentResult const& other) = default; ManagedDocumentResult& operator=(ManagedDocumentResult const& other) = default;
@ -43,9 +43,7 @@ class ManagedDocumentResult {
ManagedDocumentResult& operator=(ManagedDocumentResult&& other) noexcept { ManagedDocumentResult& operator=(ManagedDocumentResult&& other) noexcept {
_string = std::move(other._string); _string = std::move(other._string);
_vpack = other._vpack; _vpack = other._vpack;
_localDocumentId = other._localDocumentId; _revisionId = other._revisionId;
_managed = other._managed;
other.clear(); other.clear();
return *this; return *this;
} }
@ -53,51 +51,58 @@ class ManagedDocumentResult {
ManagedDocumentResult(ManagedDocumentResult&& other) noexcept ManagedDocumentResult(ManagedDocumentResult&& other) noexcept
: _string(std::move(other._string)), : _string(std::move(other._string)),
_vpack(other._vpack), _vpack(other._vpack),
_localDocumentId(other._localDocumentId), _revisionId(other._revisionId) {
_managed(other._managed) {
other.clear(); other.clear();
} }
void setUnmanaged(uint8_t const* vpack, LocalDocumentId const& documentId); /// @brief store pointer to a valid document
void setUnmanaged(uint8_t const* vpack);
/// @brief copy in a valid document
void setManaged(uint8_t const* vpack);
void setManaged(uint8_t const* vpack, LocalDocumentId const& documentId); /// @brief access the internal buffer, revisionId must be set manually
std::string* setManaged() noexcept {
std::string* setManaged(LocalDocumentId const& documentId) {
_string.clear(); _string.clear();
_vpack = nullptr; _vpack = nullptr;
_localDocumentId = documentId; _revisionId = 0;
_managed = true;
return &_string; return &_string;
} }
inline LocalDocumentId localDocumentId() const { return _localDocumentId; } inline TRI_voc_rid_t revisionId() const noexcept { return _revisionId; }
void setRevisionId(TRI_voc_rid_t rid) noexcept { _revisionId = rid; }
void setRevisionId() noexcept;
void clear() noexcept { void clearData() noexcept {
_string.clear(); _string.clear();
_vpack = nullptr; _vpack = nullptr;
_localDocumentId.clear();
_managed = false;
} }
inline uint8_t const* vpack() const { void clear() noexcept {
if (_managed) { clearData();
_revisionId = 0;
}
inline uint8_t const* vpack() const noexcept {
if (_vpack == nullptr) {
return reinterpret_cast<uint8_t const*>(_string.data()); return reinterpret_cast<uint8_t const*>(_string.data());
} }
TRI_ASSERT(_vpack != nullptr);
return _vpack; return _vpack;
} }
inline bool empty() const { return (!_managed && _vpack == nullptr); } inline bool empty() const noexcept {
return (_vpack == nullptr && _string.empty());
}
inline bool canUseInExternal() const { return !_managed; } inline bool canUseInExternal() const noexcept {
return _vpack != nullptr;
}
void addToBuilder(velocypack::Builder& builder, bool allowExternals) const; void addToBuilder(velocypack::Builder& builder, bool allowExternals) const;
private: private:
std::string _string; std::string _string;
uint8_t* _vpack; uint8_t* _vpack;
LocalDocumentId _localDocumentId; TRI_voc_rid_t _revisionId;
bool _managed;
}; };
} // namespace arangodb } // namespace arangodb

View File

@ -588,7 +588,7 @@ function runThere (options, instanceInfo, file) {
let httpOptions = pu.makeAuthorizationHeaders(options); let httpOptions = pu.makeAuthorizationHeaders(options);
httpOptions.method = 'POST'; httpOptions.method = 'POST';
httpOptions.timeout = 1800; httpOptions.timeout = 2700;
if (options.valgrind) { if (options.valgrind) {
httpOptions.timeout *= 2; httpOptions.timeout *= 2;
@ -610,7 +610,8 @@ function runThere (options, instanceInfo, file) {
(reply.message.search('timeout during read') >= 0 ) || (reply.message.search('timeout during read') >= 0 ) ||
(reply.message.search('Connection closed by remote') >= 0 ) (reply.message.search('Connection closed by remote') >= 0 )
)) { )) {
print(RED + Date() + " request timeout reached, aborting test execution" + RESET); print(RED + Date() + " request timeout reached (" + reply.message +
"), aborting test execution" + RESET);
return { return {
status: false, status: false,
message: reply.message, message: reply.message,

View File

@ -312,7 +312,7 @@ TEST_CASE("IResearchQueryTestJoinSubquery", "[iresearch][iresearch-query]") {
arangodb::ManagedDocumentResult mmdr; arangodb::ManagedDocumentResult mmdr;
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
auto const res = entities->insert(&trx, doc, mmdr, opt, tick, false); auto const res = entities->insert(&trx, doc, mmdr, opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
} }
@ -329,7 +329,7 @@ TEST_CASE("IResearchQueryTestJoinSubquery", "[iresearch][iresearch-query]") {
arangodb::ManagedDocumentResult mmdr; arangodb::ManagedDocumentResult mmdr;
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
auto const res = links->insert(&trx, doc, mmdr, opt, tick, false); auto const res = links->insert(&trx, doc, mmdr, opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
} }
@ -499,7 +499,7 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocsView.emplace_back(); insertedDocsView.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocsView.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocsView.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }
@ -519,7 +519,7 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocsCollection.emplace_back(); insertedDocsCollection.emplace_back();
auto const res = logicalCollection3->insert(&trx, doc, insertedDocsCollection.back(), opt, tick, false); auto const res = logicalCollection3->insert(&trx, doc, insertedDocsCollection.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
} }
@ -649,7 +649,7 @@ TEST_CASE("IResearchQueryTestJoin", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocsView.emplace_back(); insertedDocsView.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocsView.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocsView.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }
@ -669,7 +669,7 @@ TEST_CASE("IResearchQueryTestJoin", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocsCollection.emplace_back(); insertedDocsCollection.emplace_back();
auto const res = logicalCollection3->insert(&trx, doc, insertedDocsCollection.back(), opt, tick, false); auto const res = logicalCollection3->insert(&trx, doc, insertedDocsCollection.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
} }

View File

@ -271,7 +271,7 @@ TEST_CASE("IResearchQueryTestNumericTerm", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }

View File

@ -332,7 +332,7 @@ TEST_CASE("IResearchQueryTestOptimization", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = logicalCollection1->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = logicalCollection1->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }

View File

@ -300,12 +300,12 @@ TEST_CASE("IResearchQueryTestOptionsCollections", "[iresearch][iresearch-query]"
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
{ {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[0]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[0]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
{ {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[1]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[1]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
++i; ++i;
@ -959,7 +959,7 @@ TEST_CASE("IResearchQueryTestOptionsWaitForSync", "[iresearch][iresearch-query]"
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }

View File

@ -295,7 +295,7 @@ TEST_CASE("IResearchQueryTestOr", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }

View File

@ -333,7 +333,7 @@ TEST_CASE("IResearchQueryScorer", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocsView.emplace_back(); insertedDocsView.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocsView.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocsView.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }
@ -353,7 +353,7 @@ TEST_CASE("IResearchQueryScorer", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocsCollection.emplace_back(); insertedDocsCollection.emplace_back();
auto const res = logicalCollection3->insert(&trx, doc, insertedDocsCollection.back(), opt, tick, false); auto const res = logicalCollection3->insert(&trx, doc, insertedDocsCollection.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
} }

View File

@ -247,14 +247,14 @@ TEST_CASE("IResearchQueryTestSelectAll", "[iresearch][iresearch-query]") {
// insert into collection_1 // insert into collection_1
for (; i < insertedDocs.size()/2; ++i) { for (; i < insertedDocs.size()/2; ++i) {
auto const doc = arangodb::velocypack::Parser::fromJson("{ \"key\": " + std::to_string(i) + "}"); auto const doc = arangodb::velocypack::Parser::fromJson("{ \"key\": " + std::to_string(i) + "}");
auto const res = logicalCollection1->insert(&trx, doc->slice(), insertedDocs[i], opt, tick, false); auto const res = logicalCollection1->insert(&trx, doc->slice(), insertedDocs[i], opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }
// insert into collection_2 // insert into collection_2
for (; i < insertedDocs.size(); ++i) { for (; i < insertedDocs.size(); ++i) {
auto const doc = arangodb::velocypack::Parser::fromJson("{ \"key\": " + std::to_string(i) + "}"); auto const doc = arangodb::velocypack::Parser::fromJson("{ \"key\": " + std::to_string(i) + "}");
auto const res = logicalCollection1->insert(&trx, doc->slice(), insertedDocs[i], opt, tick, false); auto const res = logicalCollection1->insert(&trx, doc->slice(), insertedDocs[i], opt, false);
CHECK(res.ok()); CHECK(res.ok());
} }

View File

@ -260,7 +260,7 @@ TEST_CASE("IResearchQueryTestStartsWith", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }

View File

@ -301,7 +301,7 @@ TEST_CASE("IResearchQueryTestStringTerm", "[iresearch][iresearch-query]") {
for (auto doc : arangodb::velocypack::ArrayIterator(root)) { for (auto doc : arangodb::velocypack::ArrayIterator(root)) {
insertedDocs.emplace_back(); insertedDocs.emplace_back();
auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, tick, false); auto const res = collections[i % 2]->insert(&trx, doc, insertedDocs.back(), opt, false);
CHECK(res.ok()); CHECK(res.ok());
++i; ++i;
} }

View File

@ -2123,7 +2123,7 @@ SECTION("test_query") {
arangodb::OperationOptions options; arangodb::OperationOptions options;
for (size_t i = 1; i <= 12; ++i) { for (size_t i = 1; i <= 12; ++i) {
auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }"); auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }");
logicalCollection->insert(&trx, doc->slice(), inserted, options, tick, false); logicalCollection->insert(&trx, doc->slice(), inserted, options, false);
} }
CHECK((trx.commit().ok())); CHECK((trx.commit().ok()));
@ -2156,7 +2156,7 @@ SECTION("test_query") {
arangodb::OperationOptions options; arangodb::OperationOptions options;
for (size_t i = 13; i <= 24; ++i) { for (size_t i = 13; i <= 24; ++i) {
auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }"); auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }");
logicalCollection->insert(&trx, doc->slice(), inserted, options, tick, false); logicalCollection->insert(&trx, doc->slice(), inserted, options, false);
} }
CHECK(trx.commit().ok()); CHECK(trx.commit().ok());

View File

@ -656,7 +656,7 @@ SECTION("test_query") {
arangodb::OperationOptions options; arangodb::OperationOptions options;
for (size_t i = 1; i <= 12; ++i) { for (size_t i = 1; i <= 12; ++i) {
auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }"); auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }");
logicalCollection->insert(&trx, doc->slice(), inserted, options, tick, false); logicalCollection->insert(&trx, doc->slice(), inserted, options, false);
} }
CHECK((trx.commit().ok())); CHECK((trx.commit().ok()));
@ -696,7 +696,7 @@ SECTION("test_query") {
arangodb::OperationOptions options; arangodb::OperationOptions options;
for (size_t i = 13; i <= 24; ++i) { for (size_t i = 13; i <= 24; ++i) {
auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }"); auto doc = arangodb::velocypack::Parser::fromJson(std::string("{ \"key\": ") + std::to_string(i) + " }");
logicalCollection->insert(&trx, doc->slice(), inserted, options, tick, false); logicalCollection->insert(&trx, doc->slice(), inserted, options, false);
} }
CHECK(trx.commit().ok()); CHECK(trx.commit().ok());

View File

@ -1249,7 +1249,7 @@ TEST_CASE("IResearchViewNodeTest", "[iresearch][iresearch-view-node]") {
CHECK((trx.begin().ok())); CHECK((trx.begin().ok()));
auto json = arangodb::velocypack::Parser::fromJson("{}"); auto json = arangodb::velocypack::Parser::fromJson("{}");
auto const res = collection0->insert(&trx, json->slice(), mmdoc, opt, tick, false); auto const res = collection0->insert(&trx, json->slice(), mmdoc, opt, false);
CHECK(res.ok()); CHECK(res.ok());
CHECK((trx.commit().ok())); CHECK((trx.commit().ok()));

View File

@ -586,9 +586,8 @@ void PhysicalCollectionMock::getPropertiesVPack(arangodb::velocypack::Builder&)
arangodb::Result PhysicalCollectionMock::insert( arangodb::Result PhysicalCollectionMock::insert(
arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice, arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice,
arangodb::ManagedDocumentResult& result, arangodb::OperationOptions& options, arangodb::ManagedDocumentResult& result, arangodb::OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_tick_t& revisionId, bool lock, arangodb::KeyLockInfo* /*keyLockInfo*/,
arangodb::KeyLockInfo* /*keyLockInfo*/, std::function<void()> const& callbackDuringLock) {
std::function<arangodb::Result(void)> const& callbackDuringLock) {
TRI_ASSERT(callbackDuringLock == nullptr); // not implemented TRI_ASSERT(callbackDuringLock == nullptr); // not implemented
before(); before();
@ -606,7 +605,8 @@ arangodb::Result PhysicalCollectionMock::insert(
documents.emplace_back(std::move(builder), true); documents.emplace_back(std::move(builder), true);
arangodb::LocalDocumentId docId(documents.size()); // always > 0 arangodb::LocalDocumentId docId(documents.size()); // always > 0
result.setUnmanaged(documents.back().first.data(), docId); result.setUnmanaged(documents.back().first.data());
TRI_ASSERT(result.revisionId() == unused);
for (auto& index : _indexes) { for (auto& index : _indexes) {
if (index->type() == arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX) { if (index->type() == arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX) {
@ -753,7 +753,7 @@ arangodb::Result PhysicalCollectionMock::read(arangodb::transaction::Methods*,
arangodb::velocypack::StringRef const docKey(keySlice); arangodb::velocypack::StringRef const docKey(keySlice);
if (key == docKey) { if (key == docKey) {
result.setUnmanaged(doc.data(), arangodb::LocalDocumentId(i)); result.setUnmanaged(doc.data());
return arangodb::Result(TRI_ERROR_NO_ERROR); return arangodb::Result(TRI_ERROR_NO_ERROR);
} }
} }
@ -784,7 +784,7 @@ bool PhysicalCollectionMock::readDocument(arangodb::transaction::Methods* trx,
return false; // removed document return false; // removed document
} }
result.setUnmanaged(entry.first.data(), token); result.setUnmanaged(entry.first.data());
return true; return true;
} }
@ -812,9 +812,8 @@ bool PhysicalCollectionMock::readDocumentWithCallback(
arangodb::Result PhysicalCollectionMock::remove( arangodb::Result PhysicalCollectionMock::remove(
arangodb::transaction::Methods& trx, arangodb::velocypack::Slice slice, arangodb::transaction::Methods& trx, arangodb::velocypack::Slice slice,
arangodb::ManagedDocumentResult& previous, arangodb::OperationOptions& options, arangodb::ManagedDocumentResult& previous, arangodb::OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, arangodb::KeyLockInfo* /*keyLockInfo*/,
TRI_voc_rid_t& revisionId, arangodb::KeyLockInfo* /*keyLockInfo*/, std::function<void()> const& callbackDuringLock) {
std::function<arangodb::Result(void)> const& callbackDuringLock) {
TRI_ASSERT(callbackDuringLock == nullptr); // not implemented TRI_ASSERT(callbackDuringLock == nullptr); // not implemented
before(); before();
@ -827,14 +826,12 @@ arangodb::Result PhysicalCollectionMock::remove(
continue; // removed document continue; // removed document
} }
auto& doc = entry.first; arangodb::velocypack::Builder& doc = entry.first;
if (key == doc.slice().get(arangodb::StaticStrings::KeyString)) { if (key == doc.slice().get(arangodb::StaticStrings::KeyString)) {
TRI_voc_rid_t revId = i; // always > 0
entry.second = false; entry.second = false;
previous.setUnmanaged(doc.data(), arangodb::LocalDocumentId(revId)); previous.setUnmanaged(doc.data());
prevRev = revId; TRI_ASSERT(previous.revisionId() == TRI_ExtractRevisionId(doc.slice()));
return arangodb::Result(TRI_ERROR_NO_ERROR); // assume document was removed return arangodb::Result(TRI_ERROR_NO_ERROR); // assume document was removed
} }
@ -846,12 +843,11 @@ arangodb::Result PhysicalCollectionMock::remove(
arangodb::Result PhysicalCollectionMock::replace( arangodb::Result PhysicalCollectionMock::replace(
arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice, arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& result,
arangodb::OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, arangodb::OperationOptions& options,
bool lock, TRI_voc_rid_t& prevRev, arangodb::ManagedDocumentResult& previous) { bool lock, arangodb::ManagedDocumentResult& previous) {
before(); before();
return update(trx, newSlice, result, options, resultMarkerTick, lock, prevRev, return update(trx, newSlice, result, options, lock, previous);
previous);
} }
TRI_voc_rid_t PhysicalCollectionMock::revision(arangodb::transaction::Methods*) const { TRI_voc_rid_t PhysicalCollectionMock::revision(arangodb::transaction::Methods*) const {
@ -879,8 +875,7 @@ arangodb::Result PhysicalCollectionMock::compact() {
arangodb::Result PhysicalCollectionMock::update( arangodb::Result PhysicalCollectionMock::update(
arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice, arangodb::transaction::Methods* trx, arangodb::velocypack::Slice const newSlice,
arangodb::ManagedDocumentResult& result, arangodb::OperationOptions& options, arangodb::ManagedDocumentResult& result, arangodb::OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick, bool lock, TRI_voc_rid_t& prevRev, bool lock, arangodb::ManagedDocumentResult& previous) {
arangodb::ManagedDocumentResult& previous) {
auto key = newSlice.get(arangodb::StaticStrings::KeyString); auto key = newSlice.get(arangodb::StaticStrings::KeyString);
if (key.isNone()) { if (key.isNone()) {
return arangodb::Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); return arangodb::Result(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
@ -898,16 +893,12 @@ arangodb::Result PhysicalCollectionMock::update(
auto& doc = entry.first; auto& doc = entry.first;
if (key == doc.slice().get(arangodb::StaticStrings::KeyString)) { if (key == doc.slice().get(arangodb::StaticStrings::KeyString)) {
TRI_voc_rid_t revId = i; // always > 0
if (!options.mergeObjects) { if (!options.mergeObjects) {
entry.second = false; entry.second = false;
previous.setUnmanaged(doc.data(), arangodb::LocalDocumentId(revId)); previous.setUnmanaged(doc.data());
prevRev = revId; TRI_ASSERT(previous.revisionId() == TRI_ExtractRevisionId(doc.slice()));
TRI_voc_rid_t unused; return insert(trx, newSlice, result, options, lock, nullptr, nullptr);
return insert(trx, newSlice, result, options, resultMarkerTick, lock,
unused, nullptr, nullptr);
} }
arangodb::velocypack::Builder builder; arangodb::velocypack::Builder builder;
@ -928,12 +919,10 @@ arangodb::Result PhysicalCollectionMock::update(
builder.close(); builder.close();
entry.second = false; entry.second = false;
previous.setUnmanaged(doc.data(), arangodb::LocalDocumentId(revId)); previous.setUnmanaged(doc.data());
prevRev = revId; TRI_ASSERT(previous.revisionId() == TRI_ExtractRevisionId(doc.slice()));
TRI_voc_rid_t unused; return insert(trx, builder.slice(), result, options, lock, nullptr, nullptr);
return insert(trx, builder.slice(), result, options, resultMarkerTick,
lock, unused, nullptr, nullptr);
} }
} }

View File

@ -63,10 +63,9 @@ class PhysicalCollectionMock: public arangodb::PhysicalCollection {
arangodb::transaction::Methods* trx, arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& result,
arangodb::OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, arangodb::OperationOptions& options,
bool lock, TRI_voc_tick_t& revisionId, bool lock, arangodb::KeyLockInfo* /*keyLockInfo*/,
arangodb::KeyLockInfo* /*keyLockInfo*/, std::function<void()> const& callbackDuringLock) override;
std::function<arangodb::Result(void)> const& callbackDuringLock) override;
virtual void invokeOnAllElements(arangodb::transaction::Methods* trx, std::function<bool(arangodb::LocalDocumentId const&)> callback) override; virtual void invokeOnAllElements(arangodb::transaction::Methods* trx, std::function<bool(arangodb::LocalDocumentId const&)> callback) override;
virtual arangodb::LocalDocumentId lookupKey(arangodb::transaction::Methods*, arangodb::velocypack::Slice const&) const override; virtual arangodb::LocalDocumentId lookupKey(arangodb::transaction::Methods*, arangodb::velocypack::Slice const&) const override;
virtual size_t memory() const override; virtual size_t memory() const override;
@ -86,20 +85,16 @@ class PhysicalCollectionMock: public arangodb::PhysicalCollection {
arangodb::velocypack::Slice slice, arangodb::velocypack::Slice slice,
arangodb::ManagedDocumentResult& previous, arangodb::ManagedDocumentResult& previous,
arangodb::OperationOptions& options, arangodb::OperationOptions& options,
TRI_voc_tick_t& resultMarkerTick,
bool lock, bool lock,
TRI_voc_rid_t& prevRev,
TRI_voc_rid_t& revisionId,
arangodb::KeyLockInfo* /*keyLockInfo*/, arangodb::KeyLockInfo* /*keyLockInfo*/,
std::function<arangodb::Result(void)> const& callbackDuringLock std::function<void()> const& callbackDuringLock
) override; ) override;
virtual arangodb::Result replace( virtual arangodb::Result replace(
arangodb::transaction::Methods* trx, arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& result,
arangodb::OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, arangodb::OperationOptions& options,
bool lock, TRI_voc_rid_t& prevRev, bool lock, arangodb::ManagedDocumentResult& previous) override;
arangodb::ManagedDocumentResult& previous) override;
virtual TRI_voc_rid_t revision(arangodb::transaction::Methods* trx) const override; virtual TRI_voc_rid_t revision(arangodb::transaction::Methods* trx) const override;
virtual void setPath(std::string const&) override; virtual void setPath(std::string const&) override;
virtual arangodb::Result truncate( virtual arangodb::Result truncate(
@ -111,9 +106,8 @@ class PhysicalCollectionMock: public arangodb::PhysicalCollection {
arangodb::transaction::Methods* trx, arangodb::transaction::Methods* trx,
arangodb::velocypack::Slice const newSlice, arangodb::velocypack::Slice const newSlice,
arangodb::ManagedDocumentResult& result, arangodb::ManagedDocumentResult& result,
arangodb::OperationOptions& options, TRI_voc_tick_t& resultMarkerTick, arangodb::OperationOptions& options,
bool lock, TRI_voc_rid_t& prevRev, bool lock, arangodb::ManagedDocumentResult& previous) override;
arangodb::ManagedDocumentResult& previous) override;
virtual void load() override {} virtual void load() override {}
virtual void unload() override {} virtual void unload() override {}
virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const& slice, bool doSync) override; virtual arangodb::Result updateProperties(arangodb::velocypack::Slice const& slice, bool doSync) override;