opt2
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 0e41307..74887dd 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
@@ -26,6 +26,7 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.internal.IgniteInterruptedCheckedException;
@@ -91,9 +92,6 @@
private static volatile boolean interrupted;
/** */
- private final AtomicBoolean destroyed = new AtomicBoolean(false);
-
- /** */
private final String name;
/** */
@@ -103,7 +101,7 @@
private final float maxFill;
/** */
- private final long metaPageId;
+ private final AtomicReference<Page> metaPageRef = new AtomicReference<>();
/** */
private final boolean canGetRowFromInner;
@@ -611,10 +609,11 @@
this.canGetRowFromInner = innerIos.latest().canGetRow(); // TODO refactor
this.innerIos = innerIos;
this.leafIos = leafIos;
- this.metaPageId = metaPageId;
this.name = name;
this.reuseList = reuseList;
this.globalRmvId = globalRmvId;
+
+ metaPageRef.set(page(metaPageId));
}
/**
@@ -646,11 +645,9 @@
}
// Initialize meta page with new root page.
- try (Page meta = page(metaPageId)) {
- Bool res = writePage(meta, this, initRoot, BPlusMetaIO.VERSIONS.latest(), wal, rootId, 0, FALSE);
+ Bool res = writePage(metaPage(), this, initRoot, BPlusMetaIO.VERSIONS.latest(), wal, rootId, 0, FALSE);
- assert res == TRUE: res;
- }
+ assert res == TRUE : res;
}
/**
@@ -698,11 +695,7 @@
private GridCursor<T> findLowerUnbounded(L upper) throws IgniteCheckedException {
ForwardCursor cursor = new ForwardCursor(null, upper);
- long firstPageId;
-
- try (Page meta = page(metaPageId)) {
- firstPageId = getFirstPageId(meta, 0); // Level 0 is always at the bottom.
- }
+ long firstPageId = getFirstPageId(metaPage(), 0); // Level 0 is always at the bottom.
try (Page first = page(firstPageId)) {
ByteBuffer buf = readLock(first); // We always merge pages backwards, the first page is never removed.
@@ -719,10 +712,22 @@
}
/**
+ * @return Meta page.
+ */
+ private Page metaPage() {
+ Page meta = metaPageRef.get();
+
+ if (meta == null)
+ throw new IllegalStateException("Tree is being concurrently destroyed: " + getName());
+
+ return meta;
+ }
+
+ /**
* Check if the tree is getting destroyed.
*/
private void checkDestroyed() {
- if (destroyed.get())
+ if (metaPageRef.get() == null)
throw new IllegalStateException("Tree is being concurrently destroyed: " + getName());
}
@@ -786,25 +791,20 @@
* @param g Get.
*/
private void doFind(Get g) throws IgniteCheckedException {
- try {
- for (;;) { // Go down with retries.
- g.init();
+ for (;;) { // Go down with retries.
+ g.init();
- switch (findDown(g, g.rootId, 0L, g.rootLvl)) {
- case RETRY:
- case RETRY_ROOT:
- checkInterrupted();
+ switch (findDown(g, g.rootId, 0L, g.rootLvl)) {
+ case RETRY:
+ case RETRY_ROOT:
+ checkInterrupted();
- continue;
+ continue;
- default:
- return;
- }
+ default:
+ return;
}
}
- finally {
- g.releaseMeta();
- }
}
/**
@@ -880,14 +880,7 @@
*/
@SuppressWarnings("unused")
public final String printTree() {
- long rootPageId;
-
- try (Page meta = page(metaPageId)) {
- rootPageId = getFirstPageId(meta, -1);
- }
- catch (IgniteCheckedException e) {
- throw new IllegalStateException(e);
- }
+ long rootPageId = getFirstPageId(metaPage(), -1);
return treePrinter.print(rootPageId);
}
@@ -899,20 +892,20 @@
long rootPageId;
int rootLvl;
- try (Page meta = page(metaPageId)) {
- rootLvl = getRootLevel(meta);
+ Page meta = metaPage();
- if (rootLvl < 0)
- fail("Root level: " + rootLvl);
+ rootLvl = getRootLevel(meta);
- validateFirstPages(meta, rootLvl);
+ if (rootLvl < 0)
+ fail("Root level: " + rootLvl);
- rootPageId = getFirstPageId(meta, rootLvl);
+ validateFirstPages(meta, rootLvl);
- validateDownPages(meta, rootPageId, 0L, rootLvl);
+ rootPageId = getFirstPageId(meta, rootLvl);
- validateDownKeys(rootPageId, null);
- }
+ validateDownPages(meta, rootPageId, 0L, rootLvl);
+
+ validateDownKeys(rootPageId, null);
}
/**
@@ -1286,7 +1279,7 @@
// If not found, then the tree grew beyond our call stack -> retry from the actual root.
if (res == RETRY || res == NOT_FOUND) {
- int root = getRootLevel(r.meta);
+ int root = getRootLevel(metaPage());
boolean checkRes = r.checkTailLevel(root);
@@ -1317,7 +1310,6 @@
}
finally {
r.releaseTail();
- r.releaseMeta();
r.reuseFreePages();
}
@@ -1460,11 +1452,9 @@
* @throws IgniteCheckedException If failed.
*/
public final int rootLevel() throws IgniteCheckedException {
- checkDestroyed();
+ Page meta = metaPage();
- try (Page meta = page(metaPageId)) {
- return getRootLevel(meta);
- }
+ return getRootLevel(meta);
}
/**
@@ -1474,13 +1464,11 @@
* @throws IgniteCheckedException If failed.
*/
public final long size() throws IgniteCheckedException {
- checkDestroyed();
+ Page meta = metaPage();
long pageId;
- try (Page meta = page(metaPageId)) {
- pageId = getFirstPageId(meta, 0); // Level 0 is always at the bottom.
- }
+ pageId = getFirstPageId(meta, 0); // Level 0 is always at the bottom.
BPlusIO<L> io = null;
@@ -1549,7 +1537,7 @@
// It must be impossible to have an insert higher than the current root,
// because we are making decision about creating new root while keeping
// write lock on current root, so it can't concurrently change.
- assert p.btmLvl <= getRootLevel(p.meta);
+ assert p.btmLvl <= getRootLevel(metaPage());
checkInterrupted();
@@ -1572,9 +1560,6 @@
catch (AssertionError e) {
throw new AssertionError("Assertion error on row: " + row, e);
}
- finally {
- p.releaseMeta();
- }
}
/**
@@ -1587,17 +1572,20 @@
* @throws IgniteCheckedException If failed.
*/
public final long destroy() throws IgniteCheckedException {
- if (!markDestroyed())
+ Page meta = metaPageRef.getAndSet(null);
+
+ if (meta == null)
return 0;
- if (reuseList == null)
- return -1;
-
- DestroyBag bag = new DestroyBag();
-
+ DestroyBag bag;
long pagesCnt = 0;
- try (Page meta = page(metaPageId)) {
+ try {
+ if (reuseList == null)
+ return -1;
+
+ bag = new DestroyBag();
+
ByteBuffer metaBuf = writeLock(meta); // No checks, we must be out of use.
try {
@@ -1632,13 +1620,16 @@
while (pageId != 0);
}
- bag.addFreePage(recyclePage(metaPageId, meta, metaBuf));
+ bag.addFreePage(recyclePage(meta.id(), meta, metaBuf));
pagesCnt++;
}
finally {
writeUnlock(meta, metaBuf, true);
}
}
+ finally {
+ meta.close();
+ }
reuseList.addForRecycle(bag);
@@ -1648,26 +1639,18 @@
}
/**
- * @return {@code True} if state was changed.
- */
- protected final boolean markDestroyed() {
- return destroyed.compareAndSet(false, true);
- }
-
- /**
* @param metaBuf Meta page buffer.
* @return First page IDs.
*/
- protected Iterable<Long> getFirstPageIds(ByteBuffer metaBuf) {
- List<Long> result = new ArrayList<>();
+ private Iterable<Long> getFirstPageIds(ByteBuffer metaBuf) {
+ List<Long> res = new ArrayList<>();
BPlusMetaIO mio = BPlusMetaIO.VERSIONS.forPage(metaBuf);
- for (int lvl = mio.getRootLevel(metaBuf); lvl >= 0; lvl--) {
- result.add(mio.getFirstPageId(metaBuf, lvl));
- }
+ for (int lvl = mio.getRootLevel(metaBuf); lvl >= 0; lvl--)
+ res.add(mio.getFirstPageId(metaBuf, lvl));
- return result;
+ return res;
}
/**
@@ -1897,9 +1880,6 @@
/** Starting point root ID. May be outdated. Must be modified only in {@link Get#init()}. */
protected long rootId;
- /** Meta page. Initialized by {@link Get#init()}, released by {@link Get#releaseMeta()}. */
- protected Page meta;
-
/** */
protected L row;
@@ -1927,21 +1907,18 @@
/**
* Initialize operation.
*
- * !!! Symmetrically with this method must be called {@link Get#releaseMeta()} in {@code finally} block.
- *
* @throws IgniteCheckedException If failed.
*/
final void init() throws IgniteCheckedException {
- if (meta == null)
- meta = page(metaPageId);
-
int rootLvl;
long rootId;
+ Page meta = metaPage();
+
ByteBuffer buf = readLock(meta); // Meta can't be removed.
assert buf != null : "Failed to read lock meta page [page=" + meta + ", metaPageId=" +
- U.hexLong(metaPageId) + ']';
+ U.hexLong(meta.id()) + ']';
try {
BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(buf);
@@ -1996,16 +1973,6 @@
}
/**
- * Release meta page.
- */
- final void releaseMeta() {
- if (meta != null) {
- meta.close();
- meta = null;
- }
- }
-
- /**
* @param page Page.
* @param lvl Level.
* @return {@code true} If we can release the given page.
@@ -2268,7 +2235,7 @@
wal.log(new FixCountRecord(cacheId, page.id(), cnt - 1));
}
- if (!hadFwd && lvl == getRootLevel(meta)) { // We are splitting root.
+ if (!hadFwd && lvl == getRootLevel(metaPage())) { // We are splitting root.
long newRootId = allocatePage(bag);
try (Page newRoot = page(newRootId)) {
@@ -2296,7 +2263,7 @@
}
}
- Bool res = writePage(meta, BPlusTree.this, addRoot, newRootId, lvl + 1, FALSE);
+ Bool res = writePage(metaPage(), BPlusTree.this, addRoot, newRootId, lvl + 1, FALSE);
assert res == TRUE: res;
@@ -2617,7 +2584,7 @@
assert needReplaceInner != TRUE;
- if (tail.getCount() == 0 && tail.lvl != 0 && getRootLevel(meta) == tail.lvl) {
+ if (tail.getCount() == 0 && tail.lvl != 0 && getRootLevel(metaPage()) == tail.lvl) {
// Free root if it became empty after merge.
cutRoot(tail.lvl);
freePage(tail.page, tail.buf, false);
@@ -2988,7 +2955,7 @@
* @throws IgniteCheckedException If failed.
*/
private void cutRoot(int lvl) throws IgniteCheckedException {
- Bool res = writePage(meta, BPlusTree.this, cutRoot, null, lvl, FALSE);
+ Bool res = writePage(metaPage(), BPlusTree.this, cutRoot, null, lvl, FALSE);
assert res == TRUE: res;
}