mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'spdvpk' of ssh://github.com/ArangoDB/ArangoDB into spdvpk
This commit is contained in:
commit
a40729bff3
|
@ -189,12 +189,11 @@ std::string RestImportHandler::buildParseError(size_t i,
|
|||
/// @brief process a single VelocyPack document
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int RestImportHandler::handleSingleDocument(RestImportTransaction& trx,
|
||||
RestImportResult& result,
|
||||
char const* lineStart,
|
||||
VPackSlice const& slice,
|
||||
bool isEdgeCollection,
|
||||
bool waitForSync, size_t i) {
|
||||
int RestImportHandler::handleSingleDocument(
|
||||
RestImportTransaction& trx, RestImportResult& result, char const* lineStart,
|
||||
VPackSlice const& slice, std::string const& collectionName,
|
||||
bool isEdgeCollection, OperationOptions const& opOptions, size_t i) {
|
||||
|
||||
if (!slice.isObject()) {
|
||||
std::string part = VPackDumper::toString(slice);
|
||||
if (part.size() > 255) {
|
||||
|
@ -216,6 +215,8 @@ int RestImportHandler::handleSingleDocument(RestImportTransaction& trx,
|
|||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
if (isEdgeCollection) {
|
||||
// Validate from and to
|
||||
// TODO: Check if this is unified in trx.insert
|
||||
std::string from;
|
||||
std::string to;
|
||||
|
||||
|
@ -240,39 +241,14 @@ int RestImportHandler::handleSingleDocument(RestImportTransaction& trx,
|
|||
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
|
||||
}
|
||||
|
||||
TRI_document_edge_t edge;
|
||||
|
||||
edge._fromCid = 0;
|
||||
edge._toCid = 0;
|
||||
edge._fromKey = nullptr;
|
||||
edge._toKey = nullptr;
|
||||
|
||||
// Note that in a DBserver in a cluster the following two calls will
|
||||
// parse the first part as a cluster-wide collection name:
|
||||
int res1 =
|
||||
parseDocumentId(trx.resolver(), from, edge._fromCid, edge._fromKey);
|
||||
int res2 = parseDocumentId(trx.resolver(), to, edge._toCid, edge._toKey);
|
||||
|
||||
if (res1 == TRI_ERROR_NO_ERROR && res2 == TRI_ERROR_NO_ERROR) {
|
||||
res = trx.insert(trx.trxCollection(), &document, slice, &edge, waitForSync);
|
||||
} else {
|
||||
res = (res1 != TRI_ERROR_NO_ERROR ? res1 : res2);
|
||||
}
|
||||
|
||||
if (edge._fromKey != nullptr) {
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, edge._fromKey);
|
||||
}
|
||||
if (edge._toKey != nullptr) {
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, edge._toKey);
|
||||
}
|
||||
} else {
|
||||
// do not acquire an extra lock
|
||||
res = trx.insert(trx.trxCollection(), &document, slice, nullptr, waitForSync);
|
||||
}
|
||||
OperationResult opResult = trx.insert(collectionName, slice, opOptions);
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
if (opResult.successful()) {
|
||||
++result._numCreated;
|
||||
}
|
||||
res = opResult.code;
|
||||
|
||||
// special behavior in case of unique constraint violation . . .
|
||||
if (res == TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED &&
|
||||
|
@ -284,47 +260,20 @@ int RestImportHandler::handleSingleDocument(RestImportTransaction& trx,
|
|||
|
||||
std::string keyString = keySlice.copyString();
|
||||
if (_onDuplicateAction == DUPLICATE_UPDATE) {
|
||||
// update: first read existing document
|
||||
TRI_doc_mptr_copy_t previous;
|
||||
int res2 = trx.document(trx.trxCollection(), &previous, keyString);
|
||||
|
||||
if (res2 == TRI_ERROR_NO_ERROR) {
|
||||
auto shaper =
|
||||
trx.documentCollection()->getShaper(); // PROTECTED by trx here
|
||||
|
||||
TRI_shaped_json_t shapedJson;
|
||||
TRI_EXTRACT_SHAPED_JSON_MARKER(
|
||||
shapedJson, previous.getDataPtr()); // PROTECTED by trx here
|
||||
std::unique_ptr<TRI_json_t> old(
|
||||
TRI_JsonShapedJson(shaper, &shapedJson));
|
||||
|
||||
// default value
|
||||
res = TRI_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (old != nullptr) {
|
||||
std::unique_ptr<TRI_json_t> json(
|
||||
arangodb::basics::VelocyPackHelper::velocyPackToJson(slice));
|
||||
std::unique_ptr<TRI_json_t> patchedJson(TRI_MergeJson(
|
||||
TRI_UNKNOWN_MEM_ZONE, old.get(), json.get(), false, true));
|
||||
|
||||
if (patchedJson != nullptr) {
|
||||
res = trx.update(trx.trxCollection(), keyString, 0, &document, patchedJson.get(),
|
||||
TRI_DOC_UPDATE_LAST_WRITE, 0, nullptr, waitForSync);
|
||||
}
|
||||
}
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
// update
|
||||
opResult = trx.update(collectionName, keySlice, slice, opOptions);
|
||||
if (opResult.successful()) {
|
||||
++result._numUpdated;
|
||||
}
|
||||
}
|
||||
res = opResult.code;
|
||||
// We silently ignore all failed updates
|
||||
} else if (_onDuplicateAction == DUPLICATE_REPLACE) {
|
||||
// replace
|
||||
res = trx.update(trx.trxCollection(), keyString, 0, &document, slice,
|
||||
TRI_DOC_UPDATE_LAST_WRITE, 0, nullptr, waitForSync);
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
opResult = trx.replace(collectionName, keySlice, slice, opOptions);
|
||||
if (opResult.successful()) {
|
||||
++result._numUpdated;
|
||||
}
|
||||
res = opResult.code;
|
||||
} else {
|
||||
// simply ignore unique key violations silently
|
||||
TRI_ASSERT(_onDuplicateAction == DUPLICATE_IGNORE);
|
||||
|
@ -368,9 +317,10 @@ bool RestImportHandler::createFromJson(std::string const& type) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool const waitForSync = extractWaitForSync();
|
||||
bool const complete = extractComplete();
|
||||
bool const overwrite = extractOverwrite();
|
||||
OperationOptions opOptions;
|
||||
opOptions.waitForSync = extractWaitForSync();
|
||||
|
||||
// extract the collection name
|
||||
bool found;
|
||||
|
@ -509,7 +459,7 @@ bool RestImportHandler::createFromJson(std::string const& type) {
|
|||
}
|
||||
|
||||
res = handleSingleDocument(trx, result, oldPtr, builder->slice(),
|
||||
isEdgeCollection, waitForSync, i);
|
||||
collection, isEdgeCollection, opOptions, i);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (complete) {
|
||||
|
@ -548,8 +498,8 @@ bool RestImportHandler::createFromJson(std::string const& type) {
|
|||
for (VPackValueLength i = 0; i < n; ++i) {
|
||||
VPackSlice const slice = documents.at(i);
|
||||
|
||||
res = handleSingleDocument(trx, result, nullptr, slice, isEdgeCollection,
|
||||
waitForSync, i + 1);
|
||||
res = handleSingleDocument(trx, result, nullptr, slice, collection,
|
||||
isEdgeCollection, opOptions, i + 1);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (complete) {
|
||||
|
@ -595,9 +545,10 @@ bool RestImportHandler::createFromKeyValueList() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool const waitForSync = extractWaitForSync();
|
||||
bool const complete = extractComplete();
|
||||
bool const overwrite = extractOverwrite();
|
||||
OperationOptions opOptions;
|
||||
opOptions.waitForSync = extractWaitForSync();
|
||||
|
||||
// extract the collection name
|
||||
bool found;
|
||||
|
@ -753,7 +704,7 @@ bool RestImportHandler::createFromKeyValueList() {
|
|||
createVelocyPackObject(keys, values, errorMsg, i);
|
||||
res =
|
||||
handleSingleDocument(trx, result, lineStart, objectBuilder->slice(),
|
||||
isEdgeCollection, waitForSync, i);
|
||||
collection, isEdgeCollection, opOptions, i);
|
||||
} catch (...) {
|
||||
// raise any error
|
||||
res = TRI_ERROR_INTERNAL;
|
||||
|
|
|
@ -108,7 +108,8 @@ class RestImportHandler : public RestVocbaseBaseHandler {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int handleSingleDocument(RestImportTransaction&, RestImportResult&,
|
||||
char const*, VPackSlice const&, bool, bool, size_t);
|
||||
char const*, VPackSlice const&, std::string const&,
|
||||
bool, OperationOptions const&, size_t);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates documents by JSON objects
|
||||
|
|
|
@ -419,7 +419,7 @@ int Transaction::readSlice(TRI_transaction_collection_t* trxCollection,
|
|||
|
||||
OperationResult Transaction::document(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
TRI_ASSERT(getStatus() == TRI_TRANSACTION_RUNNING);
|
||||
|
||||
if (!value.isObject() && !value.isArray()) {
|
||||
|
@ -445,7 +445,7 @@ OperationResult Transaction::document(std::string const& collectionName,
|
|||
|
||||
OperationResult Transaction::documentCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
// TODO
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
@ -456,9 +456,65 @@ OperationResult Transaction::documentCoordinator(std::string const& collectionNa
|
|||
|
||||
OperationResult Transaction::documentLocal(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
// TODO
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
OperationOptions& options) {
|
||||
TRI_voc_cid_t cid = resolver()->getCollectionId(collectionName);
|
||||
|
||||
if (cid == 0) {
|
||||
return OperationResult(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
std::string key;
|
||||
TRI_voc_rid_t expectedRevision = 0;
|
||||
|
||||
// extract _key
|
||||
if (value.isObject()) {
|
||||
VPackSlice k = value.get(TRI_VOC_ATTRIBUTE_KEY);
|
||||
if (!k.isString()) {
|
||||
return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
|
||||
}
|
||||
key = k.copyString();
|
||||
|
||||
// extract _rev
|
||||
VPackSlice r = value.get(TRI_VOC_ATTRIBUTE_REV);
|
||||
if (!r.isNone()) {
|
||||
if (r.isString()) {
|
||||
expectedRevision = arangodb::basics::StringUtils::uint64(r.copyString());
|
||||
}
|
||||
else if (r.isInteger()) {
|
||||
expectedRevision = r.getNumber<TRI_voc_rid_t>();
|
||||
}
|
||||
}
|
||||
} else if (value.isString()) {
|
||||
key = value.copyString();
|
||||
} else {
|
||||
return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
|
||||
}
|
||||
|
||||
// TODO: clean this up
|
||||
TRI_document_collection_t* document = documentCollection(trxCollection(cid));
|
||||
|
||||
if (orderDitch(trxCollection(cid)) == nullptr) {
|
||||
return OperationResult(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
TRI_doc_mptr_copy_t mptr;
|
||||
int res = document->read(this, key, &mptr, !isLocked(document, TRI_TRANSACTION_READ));
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return OperationResult(res);
|
||||
}
|
||||
|
||||
TRI_ASSERT(mptr.getDataPtr() != nullptr);
|
||||
if (expectedRevision != 0 && expectedRevision != mptr._rid) {
|
||||
return OperationResult(TRI_ERROR_ARANGO_CONFLICT);
|
||||
}
|
||||
|
||||
VPackBuilder resultBuilder;
|
||||
if (!options.silent) {
|
||||
resultBuilder.add(VPackValue(mptr.vpack()));
|
||||
}
|
||||
|
||||
return OperationResult(TRI_ERROR_NO_ERROR, resultBuilder.steal());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -482,11 +538,13 @@ OperationResult Transaction::insert(std::string const& collectionName,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
OperationOptions optionsCopy = options;
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
return insertCoordinator(collectionName, value, options);
|
||||
return insertCoordinator(collectionName, value, optionsCopy);
|
||||
}
|
||||
|
||||
return insertLocal(collectionName, value, options);
|
||||
return insertLocal(collectionName, value, optionsCopy);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -497,7 +555,7 @@ OperationResult Transaction::insert(std::string const& collectionName,
|
|||
|
||||
OperationResult Transaction::insertCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
// TODO
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
@ -510,7 +568,7 @@ OperationResult Transaction::insertCoordinator(std::string const& collectionName
|
|||
|
||||
OperationResult Transaction::insertLocal(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
|
||||
TRI_voc_cid_t cid = resolver()->getCollectionId(collectionName);
|
||||
|
||||
|
@ -518,22 +576,20 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
|
|||
return OperationResult(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
// TODO: clean this up
|
||||
TRI_document_collection_t* document = documentCollection(trxCollection(cid));
|
||||
|
||||
|
||||
// add missing attributes for document (_id, _rev, _key)
|
||||
VPackBuilder merge;
|
||||
merge.openObject();
|
||||
|
||||
// generate a new tick value
|
||||
TRI_voc_tick_t const tick = TRI_NewTickServer();
|
||||
TRI_voc_tick_t const revisionId = TRI_NewTickServer();
|
||||
// TODO: clean this up
|
||||
TRI_document_collection_t* document = documentCollection(trxCollection(cid));
|
||||
|
||||
auto key = value.get(TRI_VOC_ATTRIBUTE_KEY);
|
||||
|
||||
if (key.isNone()) {
|
||||
// "_key" attribute not present in object
|
||||
merge.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(document->_keyGenerator->generate(tick)));
|
||||
merge.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(document->_keyGenerator->generate(revisionId)));
|
||||
} else if (!key.isString()) {
|
||||
// "_key" present but wrong type
|
||||
return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
|
||||
|
@ -547,7 +603,7 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
|
|||
}
|
||||
|
||||
// add _rev attribute
|
||||
merge.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(tick)));
|
||||
merge.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(revisionId)));
|
||||
|
||||
// add _id attribute
|
||||
uint8_t* p = merge.add(TRI_VOC_ATTRIBUTE_ID, VPackValuePair(9ULL, VPackValueType::Custom));
|
||||
|
@ -559,8 +615,12 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
|
|||
VPackBuilder toInsert = VPackCollection::merge(value, merge.slice(), false, false);
|
||||
VPackSlice insertSlice = toInsert.slice();
|
||||
|
||||
if (orderDitch(trxCollection(cid)) == nullptr) {
|
||||
return OperationResult(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
TRI_doc_mptr_copy_t mptr;
|
||||
int res = document->insert(this, &insertSlice, &mptr, !isLocked(document, TRI_TRANSACTION_WRITE), options.waitForSync);
|
||||
int res = document->insert(this, &insertSlice, &mptr, options, !isLocked(document, TRI_TRANSACTION_WRITE));
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return OperationResult(res);
|
||||
|
@ -581,6 +641,13 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
|
|||
return OperationResult(TRI_ERROR_NO_ERROR, resultBuilder.steal());
|
||||
}
|
||||
|
||||
OperationResult Transaction::replace(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& updateValue,
|
||||
OperationOptions const& options) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief update/patch one or multiple documents in a collection
|
||||
/// the single-document variant of this operation will either succeed or,
|
||||
|
@ -608,11 +675,13 @@ OperationResult Transaction::update(std::string const& collectionName,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
OperationOptions optionsCopy = options;
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
return updateCoordinator(collectionName, oldValue, newValue, options);
|
||||
return updateCoordinator(collectionName, oldValue, newValue, optionsCopy);
|
||||
}
|
||||
|
||||
return updateLocal(collectionName, oldValue, newValue, options);
|
||||
return updateLocal(collectionName, oldValue, newValue, optionsCopy);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -624,7 +693,7 @@ OperationResult Transaction::update(std::string const& collectionName,
|
|||
OperationResult Transaction::updateCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
// TODO
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
@ -638,9 +707,84 @@ OperationResult Transaction::updateCoordinator(std::string const& collectionName
|
|||
OperationResult Transaction::updateLocal(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
OperationOptions const& options) {
|
||||
// TODO
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
OperationOptions& options) {
|
||||
TRI_voc_cid_t cid = resolver()->getCollectionId(collectionName);
|
||||
|
||||
if (cid == 0) {
|
||||
return OperationResult(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
// generate a new tick value
|
||||
TRI_voc_tick_t const revisionId = TRI_NewTickServer();
|
||||
// TODO: clean this up
|
||||
TRI_document_collection_t* document = documentCollection(trxCollection(cid));
|
||||
|
||||
TRI_voc_rid_t expectedRevision = 0;
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
|
||||
VPackObjectIterator it(newValue);
|
||||
while (it.valid()) {
|
||||
// let all but the system attributes pass
|
||||
std::string key = it.key().copyString();
|
||||
if (key[0] != '_' ||
|
||||
(key != TRI_VOC_ATTRIBUTE_KEY &&
|
||||
key != TRI_VOC_ATTRIBUTE_ID &&
|
||||
key != TRI_VOC_ATTRIBUTE_REV &&
|
||||
key != TRI_VOC_ATTRIBUTE_FROM &&
|
||||
key != TRI_VOC_ATTRIBUTE_TO)) {
|
||||
builder.add(it.key().copyString(), it.value());
|
||||
} else if (key == TRI_VOC_ATTRIBUTE_REV) {
|
||||
if (it.value().isString()) {
|
||||
expectedRevision = arangodb::basics::StringUtils::uint64(it.value().copyString());
|
||||
}
|
||||
else if (it.value().isInteger()) {
|
||||
expectedRevision = it.value().getNumber<TRI_voc_rid_t>();
|
||||
}
|
||||
}
|
||||
it.next();
|
||||
}
|
||||
// finally add (new) _rev attribute
|
||||
builder.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(revisionId)));
|
||||
builder.close();
|
||||
|
||||
VPackSlice sanitized = builder.slice();
|
||||
|
||||
if (orderDitch(trxCollection(cid)) == nullptr) {
|
||||
return OperationResult(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
TRI_doc_mptr_copy_t mptr;
|
||||
TRI_voc_rid_t actualRevision = 0;
|
||||
TRI_doc_update_policy_t policy(expectedRevision == 0 ? TRI_DOC_UPDATE_LAST_WRITE : TRI_DOC_UPDATE_ERROR, expectedRevision, &actualRevision);
|
||||
|
||||
int res = lock(trxCollection(cid), TRI_TRANSACTION_WRITE);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return OperationResult(res);
|
||||
}
|
||||
|
||||
res = document->update(this, &oldValue, &sanitized, &mptr, &policy, options, !isLocked(document, TRI_TRANSACTION_WRITE));
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return OperationResult(res);
|
||||
}
|
||||
|
||||
TRI_ASSERT(mptr.getDataPtr() != nullptr);
|
||||
|
||||
VPackSlice vpack(mptr.vpack());
|
||||
std::string resultKey = VPackSlice(mptr.vpack()).get(TRI_VOC_ATTRIBUTE_KEY).copyString();
|
||||
|
||||
VPackBuilder resultBuilder;
|
||||
resultBuilder.openObject();
|
||||
resultBuilder.add(TRI_VOC_ATTRIBUTE_ID, VPackValue(std::string(collectionName + "/" + resultKey)));
|
||||
resultBuilder.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(vpack.get(TRI_VOC_ATTRIBUTE_REV).copyString()));
|
||||
// resultBuilder.add("_oldRev", VPackValue(vpack.get(TRI_VOC_ATTRIBUTE_REV).copyString())); // TODO
|
||||
resultBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(resultKey));
|
||||
resultBuilder.close();
|
||||
|
||||
return OperationResult(TRI_ERROR_NO_ERROR, resultBuilder.steal());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -664,11 +808,13 @@ OperationResult Transaction::remove(std::string const& collectionName,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
OperationOptions optionsCopy = options;
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
return removeCoordinator(collectionName, value, options);
|
||||
return removeCoordinator(collectionName, value, optionsCopy);
|
||||
}
|
||||
|
||||
return removeLocal(collectionName, value, options);
|
||||
return removeLocal(collectionName, value, optionsCopy);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -679,7 +825,7 @@ OperationResult Transaction::remove(std::string const& collectionName,
|
|||
|
||||
OperationResult Transaction::removeCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
// TODO
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
@ -692,7 +838,7 @@ OperationResult Transaction::removeCoordinator(std::string const& collectionName
|
|||
|
||||
OperationResult Transaction::removeLocal(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options) {
|
||||
OperationOptions& options) {
|
||||
TRI_voc_cid_t cid = resolver()->getCollectionId(collectionName);
|
||||
|
||||
if (cid == 0) {
|
||||
|
@ -714,7 +860,7 @@ OperationResult Transaction::removeLocal(std::string const& collectionName,
|
|||
if (!k.isString()) {
|
||||
return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
|
||||
}
|
||||
builder.add(TRI_VOC_ATTRIBUTE_KEY, value);
|
||||
builder.add(TRI_VOC_ATTRIBUTE_KEY, k);
|
||||
|
||||
VPackSlice r = value.get(TRI_VOC_ATTRIBUTE_REV);
|
||||
if (!r.isNone()) {
|
||||
|
@ -737,7 +883,7 @@ OperationResult Transaction::removeLocal(std::string const& collectionName,
|
|||
|
||||
TRI_voc_rid_t actualRevision = 0;
|
||||
TRI_doc_update_policy_t updatePolicy(expectedRevision == 0 ? TRI_DOC_UPDATE_LAST_WRITE : TRI_DOC_UPDATE_ERROR, expectedRevision, &actualRevision);
|
||||
int res = document->remove(this, &removeSlice, &updatePolicy, !isLocked(document, TRI_TRANSACTION_WRITE), options.waitForSync);
|
||||
int res = document->remove(this, &removeSlice, &updatePolicy, options, !isLocked(document, TRI_TRANSACTION_WRITE));
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return OperationResult(res);
|
||||
|
|
|
@ -418,7 +418,7 @@ class Transaction {
|
|||
|
||||
OperationResult document(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create one or multiple documents in a collection
|
||||
|
@ -434,7 +434,6 @@ class Transaction {
|
|||
/// @brief update/patch one or multiple documents in a collection
|
||||
/// the single-document variant of this operation will either succeed or,
|
||||
/// if it fails, clean up after itself
|
||||
/// TODO: implement this
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OperationResult update(std::string const& collectionName,
|
||||
|
@ -446,7 +445,6 @@ class Transaction {
|
|||
/// @brief replace one or multiple documents in a collection
|
||||
/// the single-document variant of this operation will either succeed or,
|
||||
/// if it fails, clean up after itself
|
||||
/// TODO: implement this
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OperationResult replace(std::string const& collectionName,
|
||||
|
@ -739,39 +737,50 @@ class Transaction {
|
|||
|
||||
OperationResult documentCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult documentLocal(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult insertCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult insertLocal(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult updateCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult updateLocal(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult replaceCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult replaceLocal(std::string const& collectionName,
|
||||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
OperationOptions const& options);
|
||||
|
||||
OperationResult removeCoordinator(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
OperationResult removeLocal(std::string const& collectionName,
|
||||
VPackSlice const& value,
|
||||
OperationOptions const& options);
|
||||
OperationOptions& options);
|
||||
|
||||
protected:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the collection
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -180,3 +180,84 @@ bool ExtractDocumentHandle(v8::Isolate* isolate,
|
|||
// unknown value type. give up
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parse document or document handle from a v8 value (string | object)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ExtractDocumentHandle(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> const val,
|
||||
std::string& collectionName,
|
||||
VPackBuilder& builder,
|
||||
bool includeRev) {
|
||||
// reset the collection identifier and the revision
|
||||
TRI_ASSERT(collectionName.empty());
|
||||
VPackObjectBuilder guard(&builder);
|
||||
|
||||
std::unique_ptr<char[]> key;
|
||||
|
||||
// extract the document identifier and revision from a string
|
||||
if (val->IsString()) {
|
||||
bool res = ParseDocumentHandle(val, collectionName, key);
|
||||
if (res) {
|
||||
if (key.get() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
builder.add(TRI_VOC_ATTRIBUTE_KEY,
|
||||
VPackValue(reinterpret_cast<char*>(key.get())));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// extract the document identifier and revision from a document object
|
||||
if (val->IsObject()) {
|
||||
TRI_GET_GLOBALS();
|
||||
|
||||
v8::Handle<v8::Object> obj = val->ToObject();
|
||||
TRI_GET_GLOBAL_STRING(_IdKey);
|
||||
TRI_GET_GLOBAL_STRING(_KeyKey);
|
||||
if (obj->HasRealNamedProperty(_IdKey)) {
|
||||
v8::Handle<v8::Value> didVal = obj->Get(_IdKey);
|
||||
|
||||
if (!ParseDocumentHandle(didVal, collectionName, key)) {
|
||||
return false;
|
||||
}
|
||||
} else if (obj->HasRealNamedProperty(_KeyKey)) {
|
||||
v8::Handle<v8::Value> didVal = obj->Get(_KeyKey);
|
||||
|
||||
if (!ParseDocumentHandle(didVal, collectionName, key)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key.get() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// If we get here we have a valid key
|
||||
builder.add(TRI_VOC_ATTRIBUTE_KEY,
|
||||
VPackValue(reinterpret_cast<char*>(key.get())));
|
||||
|
||||
if (!includeRev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TRI_GET_GLOBAL_STRING(_RevKey);
|
||||
if (!obj->HasRealNamedProperty(_RevKey)) {
|
||||
return true;
|
||||
}
|
||||
uint64_t rid = 0;
|
||||
|
||||
rid = TRI_ObjectToUInt64(obj->Get(_RevKey), true);
|
||||
|
||||
if (rid == 0) {
|
||||
return false;
|
||||
}
|
||||
builder.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(rid)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// unknown value type. give up
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -92,4 +92,14 @@ bool ExtractDocumentHandle(v8::Isolate* isolate,
|
|||
std::string& collectionName,
|
||||
std::unique_ptr<char[]>& key, TRI_voc_rid_t& rid);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parse document or document handle from a v8 value (string | object)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ExtractDocumentHandle(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> const val,
|
||||
std::string& collectionName,
|
||||
arangodb::velocypack::Builder& builder,
|
||||
bool includeRev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "Wal/Marker.h"
|
||||
#include "Wal/Slots.h"
|
||||
|
||||
#include <velocypack/Collection.h>
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/Value.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
@ -4733,8 +4734,7 @@ TRI_ASSERT(false);
|
|||
*mptr = *header;
|
||||
}
|
||||
|
||||
TRI_ASSERT(mptr->getDataPtr() !=
|
||||
nullptr); // PROTECTED by trx in trxCollection
|
||||
TRI_ASSERT(mptr->getDataPtr() != nullptr);
|
||||
TRI_ASSERT(mptr->_rid > 0);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -5121,7 +5121,7 @@ int TRI_document_collection_t::read(Transaction* trx, std::string const& key,
|
|||
CollectionReadLocker collectionLocker(this, lock);
|
||||
|
||||
TRI_doc_mptr_t* header;
|
||||
int res = lookupDocument(trx, &slice, nullptr /* policy */, header);
|
||||
int res = lookupDocument(trx, &slice, nullptr, header);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
|
@ -5131,27 +5131,37 @@ int TRI_document_collection_t::read(Transaction* trx, std::string const& key,
|
|||
*mptr = *header;
|
||||
}
|
||||
|
||||
TRI_ASSERT(mptr->getDataPtr() !=
|
||||
nullptr); // PROTECTED by trx in trxCollection
|
||||
// TRI_ASSERT(mptr->_rid > 0);
|
||||
TRI_ASSERT(mptr->getDataPtr() != nullptr);
|
||||
TRI_ASSERT(mptr->_rid > 0);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inserts a document or edge into the collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const* slice,
|
||||
TRI_doc_mptr_copy_t* mptr,
|
||||
bool lock, bool waitForSync) {
|
||||
OperationOptions& options,
|
||||
bool lock) {
|
||||
TRI_ASSERT(mptr != nullptr);
|
||||
mptr->setDataPtr(nullptr);
|
||||
|
||||
VPackSlice const key(slice->get(TRI_VOC_ATTRIBUTE_KEY));
|
||||
uint64_t const hash = key.hash();
|
||||
|
||||
TRI_voc_rid_t revision = 0;
|
||||
{
|
||||
VPackSlice r(slice->get(TRI_VOC_ATTRIBUTE_REV));
|
||||
if (r.isString()) {
|
||||
revision = arangodb::basics::StringUtils::uint64(r.copyString());
|
||||
}
|
||||
else if (r.isInteger()) {
|
||||
revision = r.getNumber<TRI_voc_rid_t>();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<arangodb::wal::Marker> marker(
|
||||
createVPackInsertMarker(trx, slice));
|
||||
|
||||
|
@ -5190,12 +5200,12 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const* slice,
|
|||
|
||||
// update the header we got
|
||||
void* mem = operation.marker->mem();
|
||||
// header->_rid = rid; // TODO
|
||||
header->_rid = revision;
|
||||
header->_hash = hash;
|
||||
header->setDataPtr(mem); // PROTECTED by trx in trxCollection
|
||||
|
||||
// insert into indexes
|
||||
res = insertDocument(trx, header, operation, mptr, waitForSync);
|
||||
res = insertDocument(trx, header, operation, mptr, options.waitForSync);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
operation.revert();
|
||||
|
@ -5203,7 +5213,7 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const* slice,
|
|||
TRI_ASSERT(mptr->getDataPtr() !=
|
||||
nullptr); // PROTECTED by trx in trxCollection
|
||||
|
||||
if (waitForSync) {
|
||||
if (options.waitForSync) {
|
||||
markerTick = operation.tick;
|
||||
}
|
||||
}
|
||||
|
@ -5217,6 +5227,107 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const* slice,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief updates a document or edge in a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_document_collection_t::update(Transaction* trx, VPackSlice const* slice,
|
||||
VPackSlice const* newSlice,
|
||||
TRI_doc_mptr_copy_t* mptr,
|
||||
TRI_doc_update_policy_t const* policy,
|
||||
OperationOptions& options,
|
||||
bool lock) {
|
||||
// initialize the result
|
||||
TRI_ASSERT(mptr != nullptr);
|
||||
mptr->setDataPtr(nullptr);
|
||||
|
||||
TRI_voc_rid_t revisionId = TRI_NewTickServer();
|
||||
|
||||
// create a sanitized with of the replacement value
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
|
||||
VPackObjectIterator it(*slice);
|
||||
|
||||
while (it.valid()) {
|
||||
// let all but the system attributes pass
|
||||
std::string key = it.key().copyString();
|
||||
if (key[0] != '_' ||
|
||||
(key != TRI_VOC_ATTRIBUTE_KEY &&
|
||||
key != TRI_VOC_ATTRIBUTE_ID &&
|
||||
key != TRI_VOC_ATTRIBUTE_REV &&
|
||||
key != TRI_VOC_ATTRIBUTE_FROM &&
|
||||
key != TRI_VOC_ATTRIBUTE_TO)) {
|
||||
builder.add(it.key().copyString(), it.value());
|
||||
}
|
||||
it.next();
|
||||
}
|
||||
|
||||
// finally add a new value for _rev
|
||||
builder.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(revisionId)));
|
||||
builder.close();
|
||||
|
||||
VPackSlice newValues = builder.slice();
|
||||
|
||||
|
||||
TRI_voc_tick_t markerTick = 0;
|
||||
int res;
|
||||
{
|
||||
TRI_IF_FAILURE("UpdateDocumentNoLock") { return TRI_ERROR_DEBUG; }
|
||||
|
||||
arangodb::CollectionWriteLocker collectionLocker(this, lock);
|
||||
|
||||
// get the header pointer of the previous revision
|
||||
TRI_doc_mptr_t* oldHeader;
|
||||
res = lookupDocument(trx, slice, policy, oldHeader);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
TRI_IF_FAILURE("UpdateDocumentNoMarker") {
|
||||
// test what happens when no marker can be created
|
||||
return TRI_ERROR_DEBUG;
|
||||
}
|
||||
|
||||
TRI_IF_FAILURE("UpdateDocumentNoMarkerExcept") {
|
||||
// test what happens when no marker can be created
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
|
||||
// merge old and new values
|
||||
VPackBuilder builder = VPackCollection::merge(VPackSlice(oldHeader->vpack()), newValues, options.mergeObjects, !options.keepNull);
|
||||
|
||||
// create marker
|
||||
std::unique_ptr<arangodb::wal::Marker> marker(createVPackInsertMarker(trx, builder.slice()));
|
||||
|
||||
arangodb::wal::DocumentOperation operation(
|
||||
trx, marker.get(), false, this, TRI_VOC_DOCUMENT_OPERATION_UPDATE);
|
||||
operation.header = oldHeader;
|
||||
operation.init();
|
||||
|
||||
res = updateDocument(trx, revisionId, oldHeader, operation, mptr, options.waitForSync);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
operation.revert();
|
||||
} else if (options.waitForSync) {
|
||||
markerTick = operation.tick;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
TRI_ASSERT(mptr->getDataPtr() != nullptr);
|
||||
TRI_ASSERT(mptr->_rid > 0);
|
||||
}
|
||||
|
||||
if (markerTick > 0) {
|
||||
// need to wait for tick, outside the lock
|
||||
arangodb::wal::LogfileManager::instance()->slots()->waitForTick(markerTick);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes a document or edge
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5224,7 +5335,8 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const* slice,
|
|||
int TRI_document_collection_t::remove(arangodb::Transaction* trx,
|
||||
VPackSlice const* slice,
|
||||
TRI_doc_update_policy_t const* policy,
|
||||
bool lock, bool waitForSync) {
|
||||
OperationOptions& options,
|
||||
bool lock) {
|
||||
TRI_IF_FAILURE("RemoveDocumentNoMarker") {
|
||||
// test what happens when no marker can be created
|
||||
return TRI_ERROR_DEBUG;
|
||||
|
@ -5289,12 +5401,11 @@ int TRI_document_collection_t::remove(arangodb::Transaction* trx,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
|
||||
res = TRI_AddOperationTransaction(trx->getInternals(), operation,
|
||||
waitForSync);
|
||||
res = TRI_AddOperationTransaction(trx->getInternals(), operation, options.waitForSync);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
operation.revert();
|
||||
} else if (waitForSync) {
|
||||
} else if (options.waitForSync) {
|
||||
markerTick = operation.tick;
|
||||
}
|
||||
}
|
||||
|
@ -5318,6 +5429,11 @@ arangodb::wal::Marker* TRI_document_collection_t::createVPackInsertMarker(
|
|||
return marker;
|
||||
}
|
||||
|
||||
arangodb::wal::Marker* TRI_document_collection_t::createVPackInsertMarker(
|
||||
Transaction* trx, VPackSlice const& slice) {
|
||||
return createVPackInsertMarker(trx, &slice);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a vpack-based remove marker for documents / edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5330,7 +5446,7 @@ arangodb::wal::Marker* TRI_document_collection_t::createVPackRemoveMarker(
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief looks up a document by key
|
||||
/// @brief looks up a document by key, low level worker
|
||||
/// the caller must make sure the read lock on the collection is held
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -5357,8 +5473,74 @@ int TRI_document_collection_t::lookupDocument(
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief updates an existing document, low level worker
|
||||
/// the caller must make sure the write lock on the collection is held
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_document_collection_t::updateDocument(arangodb::Transaction* trx,
|
||||
TRI_voc_rid_t revisionId,
|
||||
TRI_doc_mptr_t* oldHeader,
|
||||
arangodb::wal::DocumentOperation& operation,
|
||||
TRI_doc_mptr_copy_t* mptr, bool& waitForSync) {
|
||||
|
||||
// save the old data, remember
|
||||
TRI_doc_mptr_copy_t oldData = *oldHeader;
|
||||
|
||||
// remove old document from secondary indexes
|
||||
// (it will stay in the primary index as the key won't change)
|
||||
int res = deleteSecondaryIndexes(trx, oldHeader, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
// re-enter the document in case of failure, ignore errors during rollback
|
||||
insertSecondaryIndexes(trx, oldHeader, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
// update header
|
||||
TRI_doc_mptr_t* newHeader = oldHeader;
|
||||
|
||||
// update the header. this will modify oldHeader, too !!!
|
||||
newHeader->_rid = revisionId;
|
||||
newHeader->setDataPtr(
|
||||
operation.marker->mem());
|
||||
|
||||
// insert new document into secondary indexes
|
||||
res = insertSecondaryIndexes(trx, newHeader, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
// rollback
|
||||
deleteSecondaryIndexes(trx, newHeader, true);
|
||||
|
||||
// copy back old header data
|
||||
oldHeader->copy(oldData);
|
||||
|
||||
insertSecondaryIndexes(trx, oldHeader, true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
operation.indexed();
|
||||
|
||||
TRI_IF_FAILURE("UpdateDocumentNoOperation") { return TRI_ERROR_DEBUG; }
|
||||
|
||||
TRI_IF_FAILURE("UpdateDocumentNoOperationExcept") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
|
||||
res = TRI_AddOperationTransaction(trx->getInternals(), operation, waitForSync);
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
// write new header into result
|
||||
*mptr = *((TRI_doc_mptr_t*)newHeader);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief insert a document, low level worker
|
||||
/// the caller must make sure the write lock on the collection is held
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_document_collection_t::insertDocument(
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "Basics/fasthash.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Utils/OperationOptions.h"
|
||||
#include "VocBase/collection.h"
|
||||
#include "VocBase/DatafileStatistics.h"
|
||||
#include "VocBase/Ditch.h"
|
||||
|
@ -341,17 +342,25 @@ struct TRI_document_collection_t : public TRI_collection_t {
|
|||
int read(arangodb::Transaction*, std::string const&,
|
||||
TRI_doc_mptr_copy_t*, bool);
|
||||
int insert(arangodb::Transaction*, arangodb::velocypack::Slice const*,
|
||||
TRI_doc_mptr_copy_t*, bool, bool);
|
||||
TRI_doc_mptr_copy_t*, arangodb::OperationOptions&, bool);
|
||||
int update(arangodb::Transaction*, arangodb::velocypack::Slice const*,
|
||||
arangodb::velocypack::Slice const*, TRI_doc_mptr_copy_t*,
|
||||
TRI_doc_update_policy_t const*, arangodb::OperationOptions&, bool);
|
||||
int remove(arangodb::Transaction*, arangodb::velocypack::Slice const*,
|
||||
TRI_doc_update_policy_t const*, bool, bool);
|
||||
TRI_doc_update_policy_t const*, arangodb::OperationOptions&, bool);
|
||||
|
||||
private:
|
||||
arangodb::wal::Marker* createVPackInsertMarker(
|
||||
arangodb::Transaction*, arangodb::velocypack::Slice const*);
|
||||
arangodb::wal::Marker* createVPackInsertMarker(
|
||||
arangodb::Transaction*, arangodb::velocypack::Slice const&);
|
||||
arangodb::wal::Marker* createVPackRemoveMarker(
|
||||
arangodb::Transaction*, arangodb::velocypack::Slice const*);
|
||||
int lookupDocument(arangodb::Transaction*, arangodb::velocypack::Slice const*,
|
||||
TRI_doc_update_policy_t const*, TRI_doc_mptr_t*&);
|
||||
int updateDocument(arangodb::Transaction*, TRI_voc_rid_t, TRI_doc_mptr_t*,
|
||||
arangodb::wal::DocumentOperation&,
|
||||
TRI_doc_mptr_copy_t*, bool&);
|
||||
int insertDocument(arangodb::Transaction*, TRI_doc_mptr_t*,
|
||||
arangodb::wal::DocumentOperation&, TRI_doc_mptr_copy_t*,
|
||||
bool&);
|
||||
|
|
|
@ -409,7 +409,8 @@
|
|||
array.push({
|
||||
collection: aardvark.collection,
|
||||
id: aardvark.id,
|
||||
type: aardvark.type
|
||||
type: aardvark.type,
|
||||
desc: aardvark.desc
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
collectionID: 1,
|
||||
|
||||
filters: [],
|
||||
checkCursorTimer: undefined,
|
||||
|
||||
MAX_SORT: 12000,
|
||||
|
||||
lastQuery: {},
|
||||
|
||||
sortAttribute: "_key",
|
||||
|
||||
url: '/_api/documents',
|
||||
|
@ -57,8 +57,6 @@
|
|||
},
|
||||
|
||||
setFiltersForQuery: function(bindVars) {
|
||||
var self = this;
|
||||
|
||||
if (this.filters.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
@ -112,7 +110,7 @@
|
|||
},
|
||||
|
||||
moveDocument: function (key, fromCollection, toCollection, callback) {
|
||||
var querySave, queryRemove, queryObj, bindVars = {
|
||||
var querySave, queryRemove, bindVars = {
|
||||
"@collection": fromCollection,
|
||||
"filterid": key
|
||||
}, queryObj1, queryObj2;
|
||||
|
@ -145,7 +143,7 @@
|
|||
url: '/_api/cursor',
|
||||
data: JSON.stringify(queryObj1),
|
||||
contentType: "application/json",
|
||||
success: function(data) {
|
||||
success: function() {
|
||||
// if successful remove unwanted docs
|
||||
$.ajax({
|
||||
cache: false,
|
||||
|
@ -154,13 +152,13 @@
|
|||
url: '/_api/cursor',
|
||||
data: JSON.stringify(queryObj2),
|
||||
contentType: "application/json",
|
||||
success: function(data) {
|
||||
success: function() {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
window.progressView.hide();
|
||||
},
|
||||
error: function(data) {
|
||||
error: function() {
|
||||
window.progressView.hide();
|
||||
arangoHelper.arangoError(
|
||||
"Document error", "Documents inserted, but could not be removed."
|
||||
|
@ -168,7 +166,7 @@
|
|||
}
|
||||
});
|
||||
},
|
||||
error: function(data) {
|
||||
error: function() {
|
||||
window.progressView.hide();
|
||||
arangoHelper.arangoError("Document error", "Could not move selected documents.");
|
||||
}
|
||||
|
@ -176,7 +174,6 @@
|
|||
},
|
||||
|
||||
getDocuments: function (callback) {
|
||||
window.progressView.showWithDelay(300, "Fetching documents...");
|
||||
var self = this,
|
||||
query,
|
||||
bindVars,
|
||||
|
@ -224,14 +221,14 @@
|
|||
};
|
||||
}
|
||||
|
||||
var checkCursorStatus = function(jobid) {
|
||||
$.ajax({
|
||||
cache: false,
|
||||
type: 'POST',
|
||||
async: true,
|
||||
url: '/_api/cursor',
|
||||
data: JSON.stringify(queryObj),
|
||||
contentType: "application/json",
|
||||
success: function(data) {
|
||||
type: 'PUT',
|
||||
url: '/_api/job/' + encodeURIComponent(jobid),
|
||||
contentType: 'application/json',
|
||||
success: function(data, textStatus, xhr) {
|
||||
if (xhr.status === 201) {
|
||||
window.progressView.toShow = false;
|
||||
self.clearDocuments();
|
||||
if (data.extra && data.extra.stats.fullCount !== undefined) {
|
||||
|
@ -248,12 +245,59 @@
|
|||
});
|
||||
}
|
||||
self.lastQuery = queryObj;
|
||||
callback();
|
||||
window.progressView.hide();
|
||||
|
||||
callback(false, data);
|
||||
}
|
||||
else if (xhr.status === 204) {
|
||||
self.checkCursorTimer = window.setTimeout(function() {
|
||||
checkCursorStatus(jobid);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
},
|
||||
error: function(data) {
|
||||
callback(false, data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
cache: false,
|
||||
type: 'POST',
|
||||
url: '/_api/cursor',
|
||||
data: JSON.stringify(queryObj),
|
||||
headers: {
|
||||
'x-arango-async': 'store'
|
||||
},
|
||||
contentType: "application/json",
|
||||
success: function (data, textStatus, xhr) {
|
||||
|
||||
if (xhr.getResponseHeader('x-arango-async-id')) {
|
||||
var jobid = xhr.getResponseHeader('x-arango-async-id');
|
||||
|
||||
var cancelRunningCursor = function() {
|
||||
$.ajax({
|
||||
url: '/_api/job/'+ encodeURIComponent(jobid) + "/cancel",
|
||||
type: 'PUT',
|
||||
success: function() {
|
||||
window.clearTimeout(self.checkCursorTimer);
|
||||
arangoHelper.arangoNotification("Documents", "Canceled operation.");
|
||||
$('.dataTables_empty').text('Canceled.');
|
||||
window.progressView.hide();
|
||||
arangoHelper.arangoError("Document error", "Could not fetch requested documents.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.progressView.showWithDelay(300, "Fetching documents...", cancelRunningCursor);
|
||||
|
||||
checkCursorStatus(jobid);
|
||||
}
|
||||
else {
|
||||
callback(true, data);
|
||||
}
|
||||
},
|
||||
error: function(data) {
|
||||
callback(false, data);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -263,7 +307,7 @@
|
|||
},
|
||||
|
||||
buildDownloadDocumentQuery: function() {
|
||||
var self = this, query, queryObj, bindVars;
|
||||
var query, queryObj, bindVars;
|
||||
|
||||
bindVars = {
|
||||
"@collection": this.collectionID
|
||||
|
@ -313,6 +357,7 @@
|
|||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
type: "",
|
||||
isSystem: false,
|
||||
picture: "",
|
||||
locked: false
|
||||
locked: false,
|
||||
desc: undefined
|
||||
},
|
||||
|
||||
getProperties: function () {
|
||||
|
@ -112,7 +113,7 @@
|
|||
window.arangoHelper.addAardvarkJob({
|
||||
id: xhr.getResponseHeader('x-arango-async-id'),
|
||||
type: 'index',
|
||||
desc: 'Creating index...',
|
||||
desc: 'Creating Index',
|
||||
collection: self.get("id")
|
||||
});
|
||||
callback(false, data);
|
||||
|
@ -144,7 +145,7 @@
|
|||
window.arangoHelper.addAardvarkJob({
|
||||
id: xhr.getResponseHeader('x-arango-async-id'),
|
||||
type: 'index',
|
||||
desc: 'Removing index...',
|
||||
desc: 'Removing Index',
|
||||
collection: self.get("id")
|
||||
});
|
||||
callback(false, data);
|
||||
|
|
|
@ -13,9 +13,15 @@
|
|||
<!--<img src="<%= model.get('picture') %>" height="50" width="50" alt="" class="icon">-->
|
||||
<div class="tileBadge">
|
||||
<span>
|
||||
<% if(model.get('desc')) { %>
|
||||
<div class="corneredBadge inProgress">
|
||||
<%= model.get('desc') %>
|
||||
</div>
|
||||
<% } else if (model.get('status') === "loaded") { %>
|
||||
<div class="corneredBadge <%= model.get('status') %>">
|
||||
<%= model.get('status') %>
|
||||
</div>
|
||||
<% } %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<ul id="infoTab" class="nav nav-tabs">
|
||||
<li class="active"><a href="#info" data-toggle="tab">Info</a></li>
|
||||
<li><a href="#figures" data-toggle="tab">Figures</a></li>
|
||||
<li><a href="#index" data-toggle="tab">Indexes</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="tab-content-collection-info">
|
||||
|
@ -251,48 +250,5 @@
|
|||
</table>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="index">
|
||||
<table id="collectionIndexTable">
|
||||
<tr class="figuresHeader">
|
||||
<th class="collectionInfoTh">ID</th>
|
||||
<th class="collectionInfoTh">Type</th>
|
||||
<th class="collectionInfoTh">Unique</th>
|
||||
<th class="collectionInfoTh">Sparse</th>
|
||||
<th class="collectionInfoTh">Selectivity Est.</th>
|
||||
<th class="collectionInfoTh">Fields</th>
|
||||
</tr>
|
||||
<%
|
||||
if (index) {
|
||||
var fieldString = '';
|
||||
$.each(index.indexes, function(k, v) {
|
||||
if (v.fields !== undefined) {
|
||||
fieldString = v.fields.join(", ");
|
||||
}
|
||||
|
||||
//cut index id
|
||||
var position = v.id.indexOf('/');
|
||||
var indexId = v.id.substr(position+1, v.id.length);
|
||||
var selectivity = (
|
||||
v.hasOwnProperty("selectivityEstimate") ?
|
||||
(v.selectivityEstimate * 100).toFixed(2) + "%" :
|
||||
"n/a"
|
||||
);
|
||||
var sparse = (v.hasOwnProperty("sparse") ? v.sparse : "n/a");
|
||||
%>
|
||||
<tr>
|
||||
<th class="collectionInfoTh modal-text"><%=indexId%></th>
|
||||
<th class="collectionInfoTh modal-text"><%=v.type%></th>
|
||||
<th class="collectionInfoTh modal-text"><%=v.unique%></th>
|
||||
<th class="collectionInfoTh modal-text"><%=sparse%></th>
|
||||
<th class="collectionInfoTh modal-text"><%=selectivity%></th>
|
||||
<th class="collectionInfoTh modal-text"><%=fieldString%></th>
|
||||
</tr>
|
||||
<%
|
||||
});
|
||||
}
|
||||
%>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
render: function () {
|
||||
if (this.model.get("locked")) {
|
||||
$(this.el).addClass('locked');
|
||||
$(this.el).addClass(this.model.get("lockType"));
|
||||
}
|
||||
else {
|
||||
$(this.el).removeClass('locked');
|
||||
}
|
||||
|
||||
if (this.model.get("status") === 'loading') {
|
||||
$(this.el).addClass('locked');
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
});
|
||||
model.set('locked', true);
|
||||
model.set('lockType', locked.type);
|
||||
model.set('desc', locked.desc);
|
||||
});
|
||||
|
||||
this.collection.each(function(model) {
|
||||
|
|
|
@ -55,12 +55,21 @@
|
|||
this.collectionModel = this.collectionsStore.get(colid);
|
||||
},
|
||||
|
||||
getDocsCallback: function() {
|
||||
getDocsCallback: function(error) {
|
||||
//Hide first/last pagination
|
||||
$('#documents_last').css("visibility", "hidden");
|
||||
$('#documents_first').css("visibility", "hidden");
|
||||
|
||||
if (error) {
|
||||
window.progressView.hide();
|
||||
arangoHelper.arangoError("Document error", "Could not fetch requested documents.");
|
||||
}
|
||||
else if (!error || error !== undefined){
|
||||
window.progressView.hide();
|
||||
this.drawTable();
|
||||
this.renderPaginationElements();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
events: {
|
||||
|
@ -332,11 +341,11 @@
|
|||
|
||||
getFilterContent: function () {
|
||||
var filters = [ ];
|
||||
var i;
|
||||
var i, value;
|
||||
|
||||
for (i in this.filters) {
|
||||
if (this.filters.hasOwnProperty(i)) {
|
||||
var value = $('#attribute_value' + i).val();
|
||||
value = $('#attribute_value' + i).val();
|
||||
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
|
@ -517,8 +526,6 @@
|
|||
buttons,
|
||||
tableContent
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
tableContent.push(
|
||||
|
@ -754,9 +761,6 @@
|
|||
},
|
||||
|
||||
reallyDelete: function () {
|
||||
var self = this;
|
||||
var row = $(self.target).closest("tr").get(0);
|
||||
|
||||
var deleted = false;
|
||||
var result;
|
||||
if (this.type === 'document') {
|
||||
|
@ -788,7 +792,6 @@
|
|||
this.collection.getDocuments(this.getDocsCallback.bind(this));
|
||||
$('#docDeleteModal').modal('hide');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
editModeClick: function(event) {
|
||||
|
@ -853,6 +856,7 @@
|
|||
if (this.lastCollectionName === this.collectionName) {
|
||||
if (this.activeFilter) {
|
||||
this.filterCollection();
|
||||
console.log("yes");
|
||||
this.restoreFilter();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
},
|
||||
|
||||
performAction: function() {
|
||||
if (typeof this.action === 'function') {
|
||||
this.action();
|
||||
}
|
||||
window.progressView.hide();
|
||||
},
|
||||
|
||||
|
|
|
@ -71,7 +71,13 @@ $iconsize: 50px;
|
|||
|
||||
&.locked {
|
||||
cursor: not-allowed;
|
||||
|
||||
.iconSet,
|
||||
.borderBox,
|
||||
.collection-type-icon,
|
||||
.collectionName {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.iconSet {
|
||||
span:hover {
|
||||
|
@ -226,6 +232,7 @@ $iconsize: 50px;
|
|||
|
||||
.borderBox {
|
||||
border: 1px solid $c-tile-border;
|
||||
border-bottom: 0;
|
||||
border-radius: 3px;
|
||||
height: 75px;
|
||||
position: absolute;
|
||||
|
@ -276,7 +283,6 @@ $iconsize: 50px;
|
|||
border-bottom: 16px solid $c-unloaded;
|
||||
}
|
||||
|
||||
|
||||
.deleted div {
|
||||
border-bottom: 16px solid $c-state-critical;
|
||||
}
|
||||
|
@ -323,6 +329,10 @@ $iconsize: 50px;
|
|||
border-bottom-color: $c-positive;
|
||||
}
|
||||
|
||||
&.inProgress {
|
||||
border-bottom-color: $c-progress-bar;
|
||||
}
|
||||
|
||||
&.unloaded {
|
||||
border-bottom-color: $c-unloaded;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue