You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2019/02/26 12:17:37 UTC
[ignite] 06/11: fixed concurrent tests
This is an automated email from the ASF dual-hosted git repository.
sboikov pushed a commit to branch ignite-invokeAll
in repository https://gitbox.apache.org/repos/asf/ignite.git
commit 8e87906346f26825a053bbfba69c0164b5bdda12
Author: Sergi Vladykin <se...@gmail.com>
AuthorDate: Sun Feb 24 17:51:00 2019 +0300
fixed concurrent tests
---
.../cache/persistence/tree/BPlusTree.java | 43 ++++++++++++++++------
1 file changed, 31 insertions(+), 12 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java
index 8d484ca..3d6adf2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java
@@ -3047,9 +3047,23 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements
if (cnt == 0)
return;
- // If the high level is finalized we do not need to mark lower levels.
- if (gettingHighLvl < 0 && lvl < -gettingHighLvl)
- return;
+ boolean retryJustHappened = false;
+
+ // Handle finalized high level.
+ if (gettingHighLvl < 0) {
+ // Do not need to mark levels lower than the finalized high level:
+ // we already know that the next row is in another subtree.
+ if (lvl < -gettingHighLvl)
+ return;
+
+ // We unfinalize the high level after each switch to the next row,
+ // so we can not get finalized high level from the previous processed row.
+ // The current level is higher or equal to the finalized high level,
+ // thus we have a RETRY (not RETRY_ROOT, because it resets gettingHighLvl field to rootLvl).
+ // Unfinalize the high level to handle the new tree state.
+ retryJustHappened = true;
+ gettingHighLvl = -gettingHighLvl;
+ }
// Compare the next row with the rightmost row in the page (the next search row must always be greater than the current one).
// Mark the level if the rightmost row is greater or equal to the next search row.
@@ -3058,29 +3072,34 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements
if (fwdId == 0L || compare(io, pageAddr, cnt - 1, nextRow) >= 0)
gettingHighLvl = lvl;
else {
- // Because we unfinalize it after each switch to the next row.
- assert gettingHighLvl >= 0: gettingHighLvl + " " + lvl;
+ assert gettingHighLvl >= 0;
// If the marked high level is lower then the current level, it means that we jumped high after
- // processing previous rows and comparing here the new next row for the first time. We have already
- // compared this new next row to the page bound and it known to be greater, it means that
+ // processing previous rows and comparing here the new next row for the first time.
+ // Or otherwise it was a concurrent tree modification that caused the retry in this thread.
+ //
+ // We have already compared this new next row to the page bound and it known to be greater, it means that
// the correct high level for the new next row is even higher than the current level and we do not know
- // exactly where it is. Thus, we just guess it is somewhere between lvl and rootLvl.
+ // exactly where it is. We can only guess it is somewhere between lvl and rootLvl.
+ //
// We do not want to mark high levels for more than one next row because in presence of
// concurrent modifications these levels often will be wrong, producing pointless extra work,
// there also will be space overhead of storing them.
if (gettingHighLvl <= lvl) {
assert rootLvl > lvl; // Because otherwise we must be in the root here and must end up marking level in prev branch.
- // Heuristic to guess level for the next row.
- gettingHighLvl = (lvl + rootLvl) >>> 1;
+ // Heuristic to guess the high level for the next row.
+ // We should not touch the root to avoid contention on it, thus it is good idea to have it < rootLvl.
+ gettingHighLvl = retryJustHappened ?
+ lvl + 1 : // If the retry just happened, then we may guess that the tree was not changed much.
+ (lvl + rootLvl) >>> 1; // Middle point between the root and the current level.
- assert gettingHighLvl < rootLvl; // We should not touch root to avoid contention on it.
+ // TODO Maybe we can have a better heuristic?
}
// Finalize the previous marked level since the next row is out of bounds in the current subtree.
// We do this finalization to avoid extra work on lower levels, where we already know the high level.
- gettingHighLvl = -gettingHighLvl - 1;
+ gettingHighLvl = -gettingHighLvl;
}
}