mirror of https://gitee.com/bigwinds/arangodb
parent
67dc735664
commit
4132870e49
|
@ -100,6 +100,21 @@ FOR i IN 1..1000
|
||||||
} INTO users OPTIONS { overwrite: true }
|
} INTO users OPTIONS { overwrite: true }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In contrast to the MMFiles engine, the RocksDB engine does not require collection-level
|
||||||
|
locks. Different write operations on the same collection do not block each other, as
|
||||||
|
long as there are no _write-write conficts_ on the same documents. From an application
|
||||||
|
development perspective it can be desired to have exclusive write access on collections,
|
||||||
|
to simplify the development. Note that writes do not block reads in RocksDB.
|
||||||
|
Exclusive access can also speed up modification queries, because we avoid conflict checks.
|
||||||
|
|
||||||
|
Use the *exclusive* option to achieve this effect on a per query basis:
|
||||||
|
|
||||||
|
```js
|
||||||
|
FOR doc IN collection
|
||||||
|
INSERT { myval: doc.val + 1 } INTO users
|
||||||
|
OPTIONS { exclusive: true }
|
||||||
|
```
|
||||||
|
|
||||||
Returning the inserted documents
|
Returning the inserted documents
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,23 @@ FOR i IN 1..1000
|
||||||
REMOVE { _key: CONCAT('test', i), _rev: "1287623" } IN users OPTIONS { ignoreRevs: false }
|
REMOVE { _key: CONCAT('test', i), _rev: "1287623" } IN users OPTIONS { ignoreRevs: false }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In contrast to the MMFiles engine, the RocksDB engine does not require collection-level
|
||||||
|
locks. Different write operations on the same collection do not block each other, as
|
||||||
|
long as there are no _write-write conficts_ on the same documents. From an application
|
||||||
|
development perspective it can be desired to have exclusive write access on collections,
|
||||||
|
to simplify the development. Note that writes do not block reads in RocksDB.
|
||||||
|
Exclusive access can also speed up modification queries, because we avoid conflict checks.
|
||||||
|
|
||||||
|
Use the *exclusive* option to achieve this effect on a per query basis:
|
||||||
|
|
||||||
|
```js
|
||||||
|
FOR doc IN collection
|
||||||
|
REPLACE doc._key
|
||||||
|
WITH { replaced: true }
|
||||||
|
OPTIONS { exclusive: true }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Returning the removed documents
|
Returning the removed documents
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,23 @@ FOR i IN 1..1000
|
||||||
REPLACE { _key: CONCAT('test', i), _rev: "1287623" } WITH { foobar: true } IN users OPTIONS { ignoreRevs: false }
|
REPLACE { _key: CONCAT('test', i), _rev: "1287623" } WITH { foobar: true } IN users OPTIONS { ignoreRevs: false }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
In contrast to the MMFiles engine, the RocksDB engine does not require collection-level
|
||||||
|
locks. Different write operations on the same collection do not block each other, as
|
||||||
|
long as there are no _write-write conficts_ on the same documents. From an application
|
||||||
|
development perspective it can be desired to have exclusive write access on collections,
|
||||||
|
to simplify the development. Note that writes do not block reads in RocksDB.
|
||||||
|
Exclusive access can also speed up modification queries, because we avoid conflict checks.
|
||||||
|
|
||||||
|
Use the *exclusive* option to achieve this effect on a per query basis:
|
||||||
|
|
||||||
|
```js
|
||||||
|
FOR doc IN collection
|
||||||
|
REPLACE doc._key
|
||||||
|
WITH { replaced: true } IN collection
|
||||||
|
OPTIONS { exclusive: true }
|
||||||
|
```
|
||||||
|
|
||||||
Returning the modified documents
|
Returning the modified documents
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|
|
@ -230,6 +230,23 @@ FOR i IN 1..1000
|
||||||
OPTIONS { ignoreRevs: false }
|
OPTIONS { ignoreRevs: false }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In contrast to the MMFiles engine, the RocksDB engine does not require collection-level
|
||||||
|
locks. Different write operations on the same collection do not block each other, as
|
||||||
|
long as there are no _write-write conficts_ on the same documents. From an application
|
||||||
|
development perspective it can be desired to have exclusive write access on collections,
|
||||||
|
to simplify the development. Note that writes do not block reads in RocksDB.
|
||||||
|
Exclusive access can also speed up modification queries, because we avoid conflict checks.
|
||||||
|
|
||||||
|
Use the *exclusive* option to achieve this effect on a per query basis:
|
||||||
|
|
||||||
|
```js
|
||||||
|
FOR doc IN collection
|
||||||
|
UPDATE doc
|
||||||
|
WITH { updated: true } IN collection
|
||||||
|
OPTIONS { exclusive: true }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Returning the modified documents
|
Returning the modified documents
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,23 @@ the searchExpression. Even worse, if you use an outdated `_rev` in the searchExp
|
||||||
UPSERT will trigger the INSERT path instead of the UPDATE path, because it has not found a document
|
UPSERT will trigger the INSERT path instead of the UPDATE path, because it has not found a document
|
||||||
exactly matching the searchExpression.
|
exactly matching the searchExpression.
|
||||||
|
|
||||||
|
In contrast to the MMFiles engine, the RocksDB engine does not require collection-level
|
||||||
|
locks. Different write operations on the same collection do not block each other, as
|
||||||
|
long as there are no _write-write conficts_ on the same documents. From an application
|
||||||
|
development perspective it can be desired to have exclusive write access on collections,
|
||||||
|
to simplify the development. Note that writes do not block reads in RocksDB.
|
||||||
|
Exclusive access can also speed up modification queries, because we avoid conflict checks.
|
||||||
|
|
||||||
|
Use the *exclusive* option to achieve this effect on a per query basis:
|
||||||
|
|
||||||
|
```js
|
||||||
|
FOR i IN 1..1000
|
||||||
|
UPSERT { _key: CONCAT('test', i) }
|
||||||
|
INSERT { foobar: false }
|
||||||
|
UPDATE { foobar: true }
|
||||||
|
IN users OPTIONS { exclusive: true }
|
||||||
|
```
|
||||||
|
|
||||||
Returning documents
|
Returning documents
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,8 @@ Consider some ways to minimize the required amount of storage space:
|
||||||
store one entry. This will only be beneficial if the combined documents are
|
store one entry. This will only be beneficial if the combined documents are
|
||||||
regularly retrieved together and not just subsets.
|
regularly retrieved together and not just subsets.
|
||||||
|
|
||||||
### RockDB Storage Engine
|
RockDB Storage Engine
|
||||||
|
---------------------
|
||||||
|
|
||||||
Especially for the RocksDB storage engine large documents and transactions may
|
Especially for the RocksDB storage engine large documents and transactions may
|
||||||
negatively impact the write performance:
|
negatively impact the write performance:
|
||||||
|
@ -242,10 +243,9 @@ negatively impact the write performance:
|
||||||
This means that transactions have to be split if they become too big, see the
|
This means that transactions have to be split if they become too big, see the
|
||||||
[limitations section](../Transactions/Limitations.md#with-rocksdb-storage-engine).
|
[limitations section](../Transactions/Limitations.md#with-rocksdb-storage-engine).
|
||||||
|
|
||||||
#### Improving Update Query Perfromance
|
### Improving Update Query Perfromance
|
||||||
|
|
||||||
Use the _exclusive_ query option for modifying AQL queries on a _single collection_,
|
You may use the _exclusive_ query option for modifying AQL queries, to improve the performance drastically.
|
||||||
to improve the performance drastically.
|
|
||||||
This has the downside that no concurrent writes may occur on the collection, but ArangoDB is able
|
This has the downside that no concurrent writes may occur on the collection, but ArangoDB is able
|
||||||
to use a special fast-path which should improve the performance by up to 50% for large collections.
|
to use a special fast-path which should improve the performance by up to 50% for large collections.
|
||||||
|
|
||||||
|
@ -256,5 +256,42 @@ FOR doc IN mycollection
|
||||||
OPTIONS { exclusive: true }
|
OPTIONS { exclusive: true }
|
||||||
```
|
```
|
||||||
|
|
||||||
The same naturally also applies for queries using _REPLACE_. Additionally you may be able to use
|
The same naturally also applies for queries using _REPLACE_ or _INSERT_. Additionally you may be able to use
|
||||||
the `intermediateCommitCount` option in the API to subdivide the AQL transaction into smaller batches.
|
the `intermediateCommitCount` option in the API to subdivide the AQL transaction into smaller batches.
|
||||||
|
|
||||||
|
### Read / Write Load Balance
|
||||||
|
|
||||||
|
Depending on whether your data model has a higher read- or higher write-rate you may want
|
||||||
|
to adjust some of the RocksDB specific options. Some of the most critical options to
|
||||||
|
adjust the performance and memory usage are listed below:
|
||||||
|
|
||||||
|
`--rocksdb.block-cache-size`
|
||||||
|
|
||||||
|
This is the size of the block cache in bytes. This cache is used for read operations.
|
||||||
|
Increasing the size of this may improve the performance of read heavy workloads.
|
||||||
|
You may wish to adjust this parameter to control memory usage.
|
||||||
|
|
||||||
|
`--rocksdb.write-buffer-size`
|
||||||
|
|
||||||
|
Amount of data to build up in memory before converting to a file on disk.
|
||||||
|
Larger values increase performance, especially during bulk loads.
|
||||||
|
|
||||||
|
`--rocksdb.max-write-buffer-number`
|
||||||
|
|
||||||
|
Maximum number of write buffers that built up in memory, per internal column family.
|
||||||
|
The default and the minimum number is 2, so that when 1 write buffer
|
||||||
|
is being flushed to storage, new writes can continue to the other write buffer.
|
||||||
|
|
||||||
|
`--rocksdb.total-write-buffer-size`
|
||||||
|
|
||||||
|
The total amount of data to build up in all in-memory buffers when writing into ArangoDB.
|
||||||
|
You may wish to adjust this parameter to control memory usage.
|
||||||
|
|
||||||
|
Setting this to a low value may limit the RAM that ArangoDB will use but may slow down
|
||||||
|
write heavy workloads. Setting this to 0 will not limit the size of the write-buffers.
|
||||||
|
|
||||||
|
`--rocksdb.level0-stop-trigger`
|
||||||
|
|
||||||
|
When this many files accumulate in level-0, writes will be stopped to allow compaction to catch up.
|
||||||
|
Setting this value very high may improve write throughput, but may lead to temporarily
|
||||||
|
bad read performance.
|
||||||
|
|
|
@ -162,7 +162,7 @@ per-query/per-transaction basis.
|
||||||
For AQL queries, all data-modification operations now support the `exclusive` option, e.g.
|
For AQL queries, all data-modification operations now support the `exclusive` option, e.g.
|
||||||
|
|
||||||
FOR doc IN collection
|
FOR doc IN collection
|
||||||
UPDATE doc WITH { updated: true } OPTIONS { exclusive: true }
|
UPDATE doc WITH { updated: true } IN collection OPTIONS { exclusive: true }
|
||||||
|
|
||||||
JavaScript-based transactions can specify which collections to lock exclusively in the
|
JavaScript-based transactions can specify which collections to lock exclusively in the
|
||||||
`exclusive` sub-attribute of their `collections` attribute:
|
`exclusive` sub-attribute of their `collections` attribute:
|
||||||
|
|
|
@ -543,7 +543,7 @@ Result RocksDBCollection::truncate(transaction::Methods* trx,
|
||||||
auto state = RocksDBTransactionState::toState(trx);
|
auto state = RocksDBTransactionState::toState(trx);
|
||||||
RocksDBMethods* mthds = state->rocksdbMethods();
|
RocksDBMethods* mthds = state->rocksdbMethods();
|
||||||
|
|
||||||
if (state->isExclusiveTransactionOnSingleCollection() &&
|
if (state->isOnlyExclusiveTransaction() &&
|
||||||
state->hasHint(transaction::Hints::Hint::ALLOW_RANGE_DELETE) &&
|
state->hasHint(transaction::Hints::Hint::ALLOW_RANGE_DELETE) &&
|
||||||
static_cast<RocksDBEngine*>(EngineSelectorFeature::ENGINE)->canUseRangeDeleteInWal() &&
|
static_cast<RocksDBEngine*>(EngineSelectorFeature::ENGINE)->canUseRangeDeleteInWal() &&
|
||||||
_numberDocuments >= 32 * 1024) {
|
_numberDocuments >= 32 * 1024) {
|
||||||
|
|
|
@ -87,7 +87,8 @@ Result RocksDBTransactionState::beginTransaction(transaction::Hints hints) {
|
||||||
<< "beginning " << AccessMode::typeString(_type) << " transaction";
|
<< "beginning " << AccessMode::typeString(_type) << " transaction";
|
||||||
|
|
||||||
|
|
||||||
TRI_ASSERT(!hasHint(transaction::Hints::Hint::NO_USAGE_LOCK) || !AccessMode::isWriteOrExclusive(_type));
|
TRI_ASSERT(!hasHint(transaction::Hints::Hint::NO_USAGE_LOCK) ||
|
||||||
|
!AccessMode::isWriteOrExclusive(_type));
|
||||||
|
|
||||||
if (_nestingLevel == 0) {
|
if (_nestingLevel == 0) {
|
||||||
// set hints
|
// set hints
|
||||||
|
@ -147,7 +148,7 @@ Result RocksDBTransactionState::beginTransaction(transaction::Hints hints) {
|
||||||
|
|
||||||
// with exlusive locking there is no chance of conflict
|
// with exlusive locking there is no chance of conflict
|
||||||
// with other transactions -> we can use untracked< Put/Delete methods
|
// with other transactions -> we can use untracked< Put/Delete methods
|
||||||
if (isExclusiveTransactionOnSingleCollection()) {
|
if (isOnlyExclusiveTransaction()) {
|
||||||
_rocksMethods.reset(new RocksDBTrxUntrackedMethods(this));
|
_rocksMethods.reset(new RocksDBTrxUntrackedMethods(this));
|
||||||
} else {
|
} else {
|
||||||
_rocksMethods.reset(new RocksDBTrxMethods(this));
|
_rocksMethods.reset(new RocksDBTrxMethods(this));
|
||||||
|
|
|
@ -330,8 +330,16 @@ void TransactionState::setLockedShards(std::unordered_set<std::string> const& lo
|
||||||
_lockedShards = lockedShards;
|
_lockedShards = lockedShards;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TransactionState::isExclusiveTransactionOnSingleCollection() const {
|
bool TransactionState::isOnlyExclusiveTransaction() const {
|
||||||
return ((numCollections() == 1) && (_collections[0]->accessType() == AccessMode::Type::EXCLUSIVE));
|
if (!AccessMode::isWriteOrExclusive(_type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (TransactionCollection* coll : _collections) {
|
||||||
|
if (AccessMode::isWrite(coll->accessType())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TransactionState::checkCollectionPermission(TRI_voc_cid_t cid,
|
int TransactionState::checkCollectionPermission(TRI_voc_cid_t cid,
|
||||||
|
|
|
@ -215,8 +215,8 @@ class TransactionState {
|
||||||
*/
|
*/
|
||||||
void setLockedShards(std::unordered_set<std::string> const& lockedShards);
|
void setLockedShards(std::unordered_set<std::string> const& lockedShards);
|
||||||
|
|
||||||
/// @brief whether or not a transaction is an exclusive transaction on a single collection
|
/// @brief whether or not a transaction only has exculsive or read accesses
|
||||||
bool isExclusiveTransactionOnSingleCollection() const;
|
bool isOnlyExclusiveTransaction() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// @brief find a collection in the transaction's list of collections
|
/// @brief find a collection in the transaction's list of collections
|
||||||
|
|
Loading…
Reference in New Issue