ignite-4652 - tests
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/affadf3b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/affadf3b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/affadf3b Branch: refs/heads/ignite-4652 Commit: affadf3bb2a7278f46106c4e65c4b402e0b9aa80 Parents: e03af95 Author: Sergi Vladykin <[email protected]> Authored: Thu Feb 16 17:40:23 2017 +0300 Committer: Sergi Vladykin <[email protected]> Committed: Thu Feb 16 17:40:23 2017 +0300 ---------------------------------------------------------------------- .../cache/database/tree/BPlusTree.java | 27 ++++-- .../processors/database/BPlusTreeSelfTest.java | 96 +++++++++++++++++--- 2 files changed, 100 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/affadf3b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java index c1589a6..d35e7f5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java @@ -350,10 +350,7 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements // Detach the old row if we are on a leaf page. if (lvl == 0) { - assert p.oldRow == null; - - // Get old row in leaf page to reduce contention at upper level. - p.oldRow = p.needOld ? getRow(io, pageAddr, idx) : (T)Boolean.TRUE; + assert p.oldRow == null; // The old row must be set only once. // Inner replace state must be consistent by the end of the operation. assert p.needReplaceInner == FALSE || p.needReplaceInner == DONE : p.needReplaceInner; @@ -361,15 +358,18 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements // Need to replace inner key if now we are replacing the rightmost row and have a forward page. if (canGetRowFromInner && idx + 1 == cnt && p.fwdId != 0L && p.needReplaceInner == FALSE) { // Can happen only for invoke, otherwise inner key must be replaced on the way down. - assert p.invoke; + assert p.invoke != null; // We need to restart the operation from root to perform inner replace. // On the second pass we will not get here (will avoid infinite loop) because // needReplaceInner will be DONE or our key will not be the rightmost anymore. return RETRY_ROOT; } - else - p.finish(); + + // Get old row in leaf page to reduce contention at upper level. + p.oldRow = p.needOld ? getRow(io, pageAddr, idx) : (T)Boolean.TRUE; + + p.finish(); } boolean needWal = needWalDeltaRecord(page); @@ -415,6 +415,9 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements p.btmLvl++; // Get high. p.row = moveUpRow; + if (p.invoke != null) + p.invoke.row = moveUpRow; + // Here forward page can't be concurrently removed because we keep write lock on tail which is the only // page who knows about the forward page, because it was just produced by split. p.rightId = io.getForward(pageAddr); @@ -2196,8 +2199,8 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements /** */ int shift; - /** If {@code true}, then this operation is a part of invoke. */ - boolean invoke; + /** If this operation is a part of invoke. */ + Invoke invoke; /** * @param row Row. @@ -2426,6 +2429,8 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements if (lvl == 0) // Leaf: need to stop. return true; + assert btmLvl == 0; // It can not be insert. + // If we can get full row from the inner page, we have to replace it with the new one. On the way down // we can not miss inner key even in presence of concurrent operations because of `triangle` invariant + // concurrent inner replace handling by retrying from root. @@ -2816,6 +2821,8 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements break; case REMOVE: + assert rowFound; + op = new Remove(row, false); break; @@ -2830,7 +2837,7 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements if (op != null) { op.copyFrom(this); - op.invoke = true; + op.invoke = this; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/affadf3b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java index f450d7b..9db156d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java @@ -598,28 +598,33 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { final Long x = (long)BPlusTree.randomInt(CNT); final int rnd = BPlusTree.randomInt(11); + if (i % 10_000 == 0) { +// X.println(tree.printTree()); + X.println(" --> " + i + " ++> " + x); + } + // Update map. if (!map.containsKey(x)) { if (rnd % 2 == 0) { map.put(x, x); - X.println("put0: " + x); +// X.println("put0: " + x); } else { - X.println("noop0: " + x); +// X.println("noop0: " + x); } } else { if (rnd % 2 == 0) { - X.println("put1: " + x); +// X.println("put1: " + x); } else if (rnd % 3 == 0) { map.remove(x); - X.println("rmv1: " + x); +// X.println("rmv1: " + x); } else { - X.println("noop1: " + x); +// X.println("noop1: " + x); } } @@ -670,11 +675,11 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { assertNoLocks(); - X.println(tree.printTree()); +// X.println(tree.printTree()); tree.validateTree(); -// if (i % 100 == 0) + if (i % 100 == 0) assertEqualContents(tree, map); } } @@ -1168,27 +1173,28 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { final GridStripedLock lock = new GridStripedLock(256); + final String[] ops = {"put", "rmv", "inv_put", "inv_rmv"}; + IgniteInternalFuture<?> fut = multithreadedAsync(new Callable<Object>() { @Override public Object call() throws Exception { for (int i = 0; i < loops; i++) { - Long x = (long)DataStructure.randomInt(CNT); - - boolean put = DataStructure.randomInt(2) == 0; + final Long x = (long)DataStructure.randomInt(CNT); + final int op = DataStructure.randomInt(4); if (i % 10000 == 0) - X.println(" --> " + (put ? "put " : "rmv ") + i + " " + x); + X.println(" --> " + ops[op] + "_" + i + " " + x); Lock l = lock.getLock(x.longValue()); l.lock(); try { - if (put) { + if (op == 0) { // Put. assertEquals(map.put(x, x), tree.put(x)); assertNoLocks(); } - else { + else if (op == 1) { // Remove. if (map.remove(x) != null) { assertEquals(x, tree.remove(x)); @@ -1199,6 +1205,54 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { assertNoLocks(); } + else if (op == 2) { + tree.invoke(x, new IgniteTree.InvokeClosure<Long>() { + IgniteTree.OperationType opType; + + @Override public void call(@Nullable Long row) throws IgniteCheckedException { + opType = PUT; + + if (row != null) + assertEquals(x, row); + } + + @Override public Long newRow() { + return x; + } + + @Override public IgniteTree.OperationType operationType() { + return opType; + } + }); + + map.put(x,x); + } + else if (op == 3) { + tree.invoke(x, new IgniteTree.InvokeClosure<Long>() { + IgniteTree.OperationType opType; + + @Override public void call(@Nullable Long row) throws IgniteCheckedException { + if (row != null) { + assertEquals(x, row); + opType = REMOVE; + } + else + opType = NOOP; + } + + @Override public Long newRow() { + return null; + } + + @Override public IgniteTree.OperationType operationType() { + return opType; + } + }); + + map.remove(x); + } + else + fail(); } finally { l.unlock(); @@ -1405,11 +1459,17 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { /** {@inheritDoc} */ @Override public void onBeforeReadLock(Page page) { +// X.println(" onBeforeReadLock: " + U.hexLong(page.id())); +// +// U.dumpStack(); + assertNull(beforeReadLock.put(threadId(), page.id())); } /** {@inheritDoc} */ @Override public void onReadLock(Page page, long pageAddr) { +// X.println(" onReadLock: " + U.hexLong(page.id())); + if (pageAddr != 0L) { long pageId = PageIO.getPageId(pageAddr); @@ -1423,6 +1483,8 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { /** {@inheritDoc} */ @Override public void onReadUnlock(Page page, long pageAddr) { +// X.println(" onReadUnlock: " + U.hexLong(page.id())); + checkPageId(page, pageAddr); long pageId = PageIO.getPageId(pageAddr); @@ -1432,11 +1494,17 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { /** {@inheritDoc} */ @Override public void onBeforeWriteLock(Page page) { +// X.println(" onBeforeWriteLock: " + U.hexLong(page.id())); + assertNull(beforeWriteLock.put(threadId(), page.id())); } /** {@inheritDoc} */ @Override public void onWriteLock(Page page, long pageAddr) { +// X.println(" onWriteLock: " + U.hexLong(page.id())); +// +// U.dumpStack(); + if (pageAddr != 0L) { checkPageId(page, pageAddr); @@ -1453,6 +1521,8 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { /** {@inheritDoc} */ @Override public void onWriteUnlock(Page page, long pageAddr) { +// X.println(" onWriteUnlock: " + U.hexLong(page.id())); + assertEquals(effectivePageId(page.id()), effectivePageId(PageIO.getPageId(pageAddr))); assertEquals(Long.valueOf(page.id()), locks(false).remove(page.id()));
