ignite-db - free
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/e7d7e2cf Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/e7d7e2cf Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/e7d7e2cf Branch: refs/heads/ignite-db-x-10884 Commit: e7d7e2cfad67c28ec448803239fd13ae8fbfa26e Parents: d914e21 Author: S.Vladykin <[email protected]> Authored: Fri Apr 22 01:37:11 2016 +0300 Committer: S.Vladykin <[email protected]> Committed: Fri Apr 22 01:37:11 2016 +0300 ---------------------------------------------------------------------- .../processors/cache/database/RowStore.java | 28 ++-- .../cache/database/freelist/FreeItem.java | 48 +------ .../cache/database/freelist/FreeList.java | 131 +++++++++++-------- .../cache/database/freelist/FreeTree.java | 24 +++- .../cache/database/freelist/io/FreeIO.java | 8 +- .../cache/database/freelist/io/FreeInnerIO.java | 51 +++++--- .../cache/database/freelist/io/FreeLeafIO.java | 28 ++-- .../cache/database/tree/io/DataPageIO.java | 57 +++++--- .../cache/database/tree/util/PageHandler.java | 4 +- 9 files changed, 210 insertions(+), 169 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/RowStore.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/RowStore.java index 2ea2ee4..fdfadd6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/RowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/RowStore.java @@ -54,25 +54,30 @@ public class RowStore<T extends CacheDataRow> { private volatile long lastDataPageId; /** */ + @Deprecated private final PageHandler<CacheDataRow> writeRow = new PageHandler<CacheDataRow>() { @Override public int run(Page page, ByteBuffer buf, CacheDataRow row, int ignore) throws IgniteCheckedException { int entrySize = DataPageIO.getEntrySize(coctx, row.key(), row.value()); DataPageIO io = DataPageIO.VERSIONS.forPage(buf); + if (io.isEnoughSpace(buf, entrySize)) + return -1; + int idx = io.addRow(coctx, buf, row.key(), row.value(), row.version(), entrySize); - if (idx != -1) { - row.link(linkFromDwordOffset(page.id(), idx)); + assert idx >= 0: idx; - assert row.link() != 0; - } + row.link(linkFromDwordOffset(page.id(), idx)); + + assert row.link() != 0; return idx; } }; /** */ + @Deprecated private final PageHandler<Void> rmvRow = new PageHandler<Void>() { @Override public int run(Page page, ByteBuffer buf, Void ignore, int itemId) throws IgniteCheckedException { DataPageIO io = DataPageIO.VERSIONS.forPage(buf); @@ -125,9 +130,13 @@ public class RowStore<T extends CacheDataRow> { public void removeRow(long link) throws IgniteCheckedException { assert link != 0; - try (Page page = page(pageId(link))) { - writePage(page, rmvRow, null, dwordsOffset(link), 0); + if (freeList == null) { + try (Page page = page(pageId(link))) { + writePage(page, rmvRow, null, dwordsOffset(link), 0); + } } + else + freeList.removeRow(link); } /** @@ -156,16 +165,17 @@ public class RowStore<T extends CacheDataRow> { */ public void addRow(CacheDataRow row) throws IgniteCheckedException { if (freeList == null) - writeRowData0(row); + writeRowDataOld(row); else - freeList.writeRowData(row); + freeList.insertRow(row); } /** * @param row Row. * @throws IgniteCheckedException If failed. */ - private void writeRowData0(CacheDataRow row) throws IgniteCheckedException { + @Deprecated + private void writeRowDataOld(CacheDataRow row) throws IgniteCheckedException { assert row.link() == 0; while (row.link() == 0) { http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeItem.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeItem.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeItem.java index 7de30c7..2c81074 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeItem.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeItem.java @@ -26,38 +26,17 @@ public class FreeItem extends FullPageId { /** */ private short freeSpace; - /** */ - private short dispersion; - /** * @param freeSpace Free space. - * @param dispersion Dispersion. * @param pageId Page ID. * @param cacheId Cache ID. */ - public FreeItem(short freeSpace, short dispersion, long pageId, int cacheId) { + public FreeItem(int freeSpace, long pageId, int cacheId) { super(pageId, cacheId); - assert freeSpace >= 0: freeSpace; - - this.freeSpace = freeSpace; - this.dispersion = dispersion; - } - - /** - * @param freeSpace Free space. - * @param dispersion Dispersion. - * @return Dispersed free space. - */ - public static int disperse(int freeSpace, int dispersion) { - return (freeSpace << 16) | dispersion; - } + assert freeSpace >= 0 && freeSpace <= Short.MAX_VALUE: freeSpace; - /** - * @return Dispersed free space. - */ - public int dispersedFreeSpace() { - return disperse(freeSpace, dispersion); + this.freeSpace = (short)freeSpace; } /** @@ -66,25 +45,4 @@ public class FreeItem extends FullPageId { public short freeSpace() { return freeSpace; } - - /** - * @param freeSpace Free space. - */ - public void freeSpace(short freeSpace) { - this.freeSpace = freeSpace; - } - - /** - * @return Dispersion. - */ - public short dispersion() { - return dispersion; - } - - /** - * @param dispersion Dispersion. - */ - public void dispersion(short dispersion) { - this.dispersion = dispersion; - } } http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeList.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeList.java index a7507a0..68780c2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeList.java @@ -18,11 +18,11 @@ package org.apache.ignite.internal.processors.cache.database.freelist; import java.nio.ByteBuffer; -import java.util.concurrent.ThreadLocalRandom; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.FullPageId; import org.apache.ignite.internal.pagemem.Page; import org.apache.ignite.internal.pagemem.PageIdAllocator; +import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.database.CacheDataRow; @@ -61,7 +61,41 @@ public class FreeList { assert idx >= 0; - return io.getFreeSpace(buf); + int freeSpace = io.getFreeSpace(buf); + + // Put our free item. + tree(row.partition()).put(new FreeItem(freeSpace, page.id(), cctx.cacheId())); + + return 0; + } + }; + + /** */ + private final PageHandler<FreeTree> removeRow = new PageHandler<FreeTree>() { + @Override public int run(Page page, ByteBuffer buf, FreeTree tree, int itemId) throws IgniteCheckedException { + DataPageIO io = DataPageIO.VERSIONS.forPage(buf); + + assert DataPageIO.check(itemId): itemId; + + int oldFreeSpace = io.getFreeSpace(buf); + + io.removeRow(buf, (byte)itemId); + + int newFreeSpace = io.getFreeSpace(buf); + + // Move page to the new position with respect to the new free space. + FreeItem item = tree.remove(new FreeItem(oldFreeSpace, page.id(), cctx.cacheId())); + + // If item is null, then it was removed concurrently by insertRow, because + // in removeRow we own the write lock on this page. Thus we can be sure that + // insertRow will update position correctly after us. + if (item != null) { + FreeItem old = tree.put(new FreeItem(newFreeSpace, page.id(), cctx.cacheId())); + + assert old == null; + } + + return 0; } }; @@ -83,14 +117,12 @@ public class FreeList { /** * @param tree Tree. - * @param neededSpace Needed free space. + * @param lookupItem Lookup item. * @return Free item or {@code null} if it was impossible to find one. * @throws IgniteCheckedException If failed. */ - private FreeItem take(FreeTree tree, short neededSpace) throws IgniteCheckedException { - assert neededSpace > 0 && neededSpace < Short.MAX_VALUE: neededSpace; - - FreeItem res = tree.removeCeil(new FreeItem(neededSpace, dispersion(), 0, 0)); + private FreeItem take(FreeTree tree, FreeItem lookupItem) throws IgniteCheckedException { + FreeItem res = tree.removeCeil(lookupItem); assert res == null || (res.pageId() != 0 && res.cacheId() == cctx.cacheId()): res; @@ -98,35 +130,28 @@ public class FreeList { } /** - * @return Random dispersion value. - */ - private static short dispersion() { - return (short)ThreadLocalRandom.current().nextInt(Short.MIN_VALUE, Short.MAX_VALUE); - } - - /** - * @param part Partition. + * @param partId Partition. * @return Tree. * @throws IgniteCheckedException If failed. */ - private FreeTree tree(Integer part) throws IgniteCheckedException { - assert part >= 0 && part < Short.MAX_VALUE: part; + private FreeTree tree(Integer partId) throws IgniteCheckedException { + assert partId >= 0 && partId < Short.MAX_VALUE: partId; - GridFutureAdapter<FreeTree> fut = trees.get(part); + GridFutureAdapter<FreeTree> fut = trees.get(partId); if (fut == null) { fut = new GridFutureAdapter<>(); - if (trees.putIfAbsent(part, fut) != null) - fut = trees.get(part); + if (trees.putIfAbsent(partId, fut) != null) + fut = trees.get(partId); else { // Index name will be the same across restarts. - String idxName = part + "$$" + cctx.cacheId() + "_free"; + String idxName = partId + "$$" + cctx.cacheId() + "_free"; IgniteBiTuple<FullPageId,Boolean> t = cctx.shared().database().meta() .getOrAllocateForIndex(cctx.cacheId(), idxName); - fut.onDone(new FreeTree(reuseList, cctx.cacheId(), pageMem, t.get1(), t.get2())); + fut.onDone(new FreeTree(reuseList, cctx.cacheId(), partId, pageMem, t.get1(), t.get2())); } } @@ -134,59 +159,51 @@ public class FreeList { } /** + * @param link Row link. + * @throws IgniteCheckedException + */ + public void removeRow(long link) throws IgniteCheckedException { + assert link != 0; + + long pageId = PageIdUtils.pageId(link); + int itemId = PageIdUtils.dwordsOffset(link); + + try (Page page = pageMem.page(new FullPageId(pageId, cctx.cacheId()))) { + writePage(page, removeRow, null, itemId, -1); + } + } + + /** * @param row Row. * @throws IgniteCheckedException If failed. */ - public void writeRowData(CacheDataRow row) throws IgniteCheckedException { - // assert row.link == 0; + public void insertRow(CacheDataRow row) throws IgniteCheckedException { + assert row.link() == 0: row.link(); int entrySize = DataPageIO.getEntrySize(cctx.cacheObjectContext(), row.key(), row.value()); assert entrySize > 0 && entrySize < Short.MAX_VALUE: entrySize; FreeTree tree = tree(row.partition()); - FreeItem item = take(tree, (short)entrySize); - Page page = null; - int freeSpace = -1; + // TODO add random pageIndex here for lower contention? + FreeItem item = take(tree, new FreeItem(entrySize, 0, cctx.cacheId())); - try { + try (Page page = item == null ? + allocateDataPage(row.partition()) : + pageMem.page(item) + ) { if (item == null) { DataPageIO io = DataPageIO.VERSIONS.latest(); - page = allocatePage(row.partition()); - ByteBuffer buf = page.getForInitialWrite(); io.initNewPage(buf, page.id()); - freeSpace = writeRow.run(page, buf, row, entrySize); - } - else { - page = pageMem.page(item); - - freeSpace = writePage(page, writeRow, row, entrySize, -1); - } - } - finally { - if (page != null) { - page.close(); - - if (freeSpace != -1) { // Put back to the tree. - assert freeSpace >= 0 && freeSpace < Short.MAX_VALUE: freeSpace; - - if (item == null) - item = new FreeItem((short)freeSpace, dispersion(), page.id(), cctx.cacheId()); - else { - item.freeSpace((short)freeSpace); - item.dispersion(dispersion()); - } - - FreeItem old = tree.put(item); - - assert old == null; - } + writeRow.run(page, buf, row, entrySize); } + else + writePage(page, writeRow, row, entrySize, -1); } } @@ -195,7 +212,7 @@ public class FreeList { * @return Page. * @throws IgniteCheckedException If failed. */ - private Page allocatePage(int part) throws IgniteCheckedException { + private Page allocateDataPage(int part) throws IgniteCheckedException { FullPageId pageId = pageMem.allocatePage(cctx.cacheId(), part, PageIdAllocator.FLAG_DATA); return pageMem.page(pageId); http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeTree.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeTree.java index 8af7561..c5138c5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/FreeTree.java @@ -35,6 +35,9 @@ import org.apache.ignite.internal.processors.cache.database.tree.reuse.ReuseList * Data structure for data pages and their free spaces. */ public class FreeTree extends BPlusTree<FreeItem, FreeItem> { + /** */ + private final int partId; + /** * @param reuseList Reuse list. * @param cacheId Cache ID. @@ -43,16 +46,25 @@ public class FreeTree extends BPlusTree<FreeItem, FreeItem> { * @param initNew Initialize new index. * @throws IgniteCheckedException If failed. */ - public FreeTree(ReuseList reuseList, int cacheId, PageMemory pageMem, FullPageId metaPageId, boolean initNew) + public FreeTree(ReuseList reuseList, int cacheId, int partId, PageMemory pageMem, FullPageId metaPageId, boolean initNew) throws IgniteCheckedException { super(cacheId, pageMem, metaPageId, reuseList); + this.partId = partId; + assert pageMem != null; if (initNew) initNew(); } + /** + * @return Partition ID. + */ + public int getPartId() { + return partId; + } + /** {@inheritDoc} */ @Override protected BPlusIO<FreeItem> io(int type, int ver) { if (type == PageIO.T_FREE_INNER) @@ -76,12 +88,12 @@ public class FreeTree extends BPlusTree<FreeItem, FreeItem> { /** {@inheritDoc} */ @Override protected int compare(BPlusIO<FreeItem> io, ByteBuffer buf, int idx, FreeItem row) throws IgniteCheckedException { - if (io.isLeaf()) // In a leaf we can do a fair compare. - return Short.compare(((FreeIO)io).freeSpace(buf, idx), row.freeSpace()); + int res = Short.compare(((FreeIO)io).getFreeSpace(buf, idx), row.freeSpace()); + + if (res == 0) + res = Long.compare(((FreeLeafIO)io).getPageIndex(buf, idx), FreeInnerIO.pageIndex(row.pageId())); - // In inner pages we do compare on dispersed free space to avoid contention on a single page - // when all the entries are equal and many pages have the same free space. - return Integer.compare(((FreeIO)io).dispersedFreeSpace(buf, idx), row.dispersedFreeSpace()); + return res; } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeIO.java index de28b22..d893b27 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeIO.java @@ -26,14 +26,14 @@ public interface FreeIO { /** * @param buf Buffer. * @param idx Index. - * @return Dispersed free space. + * @return Free space. */ - public int dispersedFreeSpace(ByteBuffer buf, int idx); + public short getFreeSpace(ByteBuffer buf, int idx); /** * @param buf Buffer. * @param idx Index. - * @return Free space. + * @return Page index. */ - public short freeSpace(ByteBuffer buf, int idx); + public int getPageIndex(ByteBuffer buf, int idx); } http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeInnerIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeInnerIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeInnerIO.java index b9d13b8..14c7a00 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeInnerIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeInnerIO.java @@ -1,7 +1,10 @@ package org.apache.ignite.internal.processors.cache.database.freelist.io; import java.nio.ByteBuffer; +import org.apache.ignite.internal.pagemem.PageIdAllocator; +import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.processors.cache.database.freelist.FreeItem; +import org.apache.ignite.internal.processors.cache.database.freelist.FreeTree; import org.apache.ignite.internal.processors.cache.database.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusIO; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusInnerIO; @@ -20,48 +23,62 @@ public class FreeInnerIO extends BPlusInnerIO<FreeItem> implements FreeIO { * @param ver Page format version. */ protected FreeInnerIO(int ver) { - super(T_FREE_INNER, ver, false, 4); // freeSpace(2) + dispersion(2) + super(T_FREE_INNER, ver, false, 6); // freeSpace(2) + pageIndex(4) + } + + /** + * @param pageId Page Id. + * @return Page index. + */ + public static int pageIndex(long pageId) { + long idx = PageIdUtils.pageIdx(pageId); + + assert idx >= 0 && idx < Integer.MAX_VALUE: idx; + + return (int)idx; } /** {@inheritDoc} */ @Override public void store(ByteBuffer buf, int idx, FreeItem row) { - store(buf, idx, row.dispersedFreeSpace()); + int off = offset(idx); + + buf.putShort(off, row.freeSpace()); + buf.putInt(off + 2, pageIndex(row.pageId())); } /** {@inheritDoc} */ @Override public void store(ByteBuffer dst, int dstIdx, BPlusIO<FreeItem> srcIo, ByteBuffer src, int srcIdx) { - store(dst, dstIdx, ((FreeIO)srcIo).dispersedFreeSpace(src, srcIdx)); - } + FreeIO srcFreeIo = (FreeIO)srcIo; - /** - * @param buf Buffer. - * @param idx Index. - * @param dispersedFreeSpace Dispersed free space. - */ - private void store(ByteBuffer buf, int idx, int dispersedFreeSpace) { - int off = offset(idx); + int off = offset(dstIdx); - buf.putInt(off, dispersedFreeSpace); + dst.putShort(off, srcFreeIo.getFreeSpace(src, srcIdx)); + dst.putInt(off + 2, srcFreeIo.getPageIndex(src, srcIdx)); } /** {@inheritDoc} */ - @Override public int dispersedFreeSpace(ByteBuffer buf, int idx) { + @Override public short getFreeSpace(ByteBuffer buf, int idx) { int off = offset(idx); - return buf.getInt(off); + return buf.getShort(off); } /** {@inheritDoc} */ - @Override public short freeSpace(ByteBuffer buf, int idx) { + @Override public int getPageIndex(ByteBuffer buf, int idx) { int off = offset(idx); - return buf.getShort(off); + return buf.getInt(off + 2); } /** {@inheritDoc} */ @Override public FreeItem getLookupRow(BPlusTree<FreeItem, ?> tree, ByteBuffer buf, int idx) { int off = offset(idx); - return new FreeItem(buf.getShort(off), buf.getShort(off + 2), 0, 0); + short freeSpace = buf.getShort(off); + int pageIdx = buf.getInt(off + 2); + + long pageId = PageIdUtils.pageId(((FreeTree)tree).getPartId(), PageIdAllocator.FLAG_DATA, pageIdx); + + return new FreeItem(freeSpace, pageId, tree.getCacheId()); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeLeafIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeLeafIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeLeafIO.java index 5496897..8503c7d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeLeafIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/io/FreeLeafIO.java @@ -18,10 +18,13 @@ package org.apache.ignite.internal.processors.cache.database.freelist.io; import java.nio.ByteBuffer; +import org.apache.ignite.internal.pagemem.PageIdAllocator; +import org.apache.ignite.internal.pagemem.PageIdUtils; +import org.apache.ignite.internal.processors.cache.database.freelist.FreeItem; +import org.apache.ignite.internal.processors.cache.database.freelist.FreeTree; import org.apache.ignite.internal.processors.cache.database.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusLeafIO; import org.apache.ignite.internal.processors.cache.database.tree.io.IOVersions; -import org.apache.ignite.internal.processors.cache.database.freelist.FreeItem; /** * Routines for free list leaf pages. @@ -36,35 +39,40 @@ public class FreeLeafIO extends BPlusLeafIO<FreeItem> implements FreeIO { * @param ver Page format version. */ protected FreeLeafIO(int ver) { - super(T_FREE_LEAF, ver, 12); // freeSpace(2) + dispersion(2) + pageId(8) + super(T_FREE_LEAF, ver, 6); // freeSpace(2) + pageIndex(4) } /** {@inheritDoc} */ - @Override public final void store(ByteBuffer buf, int idx, FreeItem row) { + @Override public void store(ByteBuffer buf, int idx, FreeItem row) { int off = offset(idx); - buf.putInt(off, row.dispersedFreeSpace()); - buf.putLong(off + 4, row.pageId()); + buf.putShort(off, row.freeSpace()); + buf.putInt(off + 2, FreeInnerIO.pageIndex(row.pageId())); } /** {@inheritDoc} */ - @Override public int dispersedFreeSpace(ByteBuffer buf, int idx) { + @Override public short getFreeSpace(ByteBuffer buf, int idx) { int off = offset(idx); - return buf.getInt(off); + return buf.getShort(off); } /** {@inheritDoc} */ - @Override public short freeSpace(ByteBuffer buf, int idx) { + @Override public int getPageIndex(ByteBuffer buf, int idx) { int off = offset(idx); - return buf.getShort(off); + return buf.getInt(off + 2); } /** {@inheritDoc} */ @Override public FreeItem getLookupRow(BPlusTree<FreeItem, ?> tree, ByteBuffer buf, int idx) { int off = offset(idx); - return new FreeItem(buf.getShort(off), buf.getShort(off + 2), buf.getLong(off + 4), tree.getCacheId()); + short freeSpace = buf.getShort(off); + int pageIdx = buf.getInt(off + 2); + + long pageId = PageIdUtils.pageId(((FreeTree)tree).getPartId(), PageIdAllocator.FLAG_DATA, pageIdx); + + return new FreeItem(freeSpace, pageId, tree.getCacheId()); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java index beaed49..a5efb5d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java @@ -250,9 +250,9 @@ public class DataPageIO extends PageIO { assert indirectItemIdx >= directCnt && indirectItemIdx < directCnt + indirectCnt: indirectCnt; itemId = directItemIndex(getItem(buf, indirectItemIdx)); - } - assert itemId >= 0 && itemId < directCnt: itemId; // Direct item must be here. + assert itemId >= 0 && itemId < directCnt: itemId; // Direct item must be here. + } return toOffset(getItem(buf, itemId)); } @@ -393,10 +393,17 @@ public class DataPageIO extends PageIO { return; // TODO May be have a separate list of free pages? } + // Get the entry size before the actual remove. + int rmvEntrySize = getEntrySize(buf, getDataOffset(buf, itemId), false); + if (itemId < directCnt) removeDirectItem(buf, itemId, directCnt, indirectCnt); else removeIndirectItem(buf, itemId, directCnt, indirectCnt); + + // Increase free space. + setFreeSpace(buf, getFreeSpace(buf) + rmvEntrySize + + ITEM_SIZE * (directCnt - getDirectCount(buf) + indirectCnt - getIndirectCount(buf))); } /** @@ -482,14 +489,24 @@ public class DataPageIO extends PageIO { } /** - * @param entrySize Entry size as returned by {@link #getEntrySize(int, int)}. - * @param firstOff First entry data offset. + * @param newEntrySizeWithItem New entry size as returned by {@link #getEntrySize(int, int)}. + * @param firstEntryOff First entry data offset. * @param directCnt Direct items count. * @param indirectCnt Indirect items count. * @return {@code true} If there is enough space for the entry. */ - private static boolean enoughSpaceForEntry(int entrySize, int firstOff, int directCnt, int indirectCnt) { - return ITEMS_OFF + ITEM_SIZE * (directCnt + indirectCnt) <= firstOff - entrySize; + public static boolean isEnoughSpace(int newEntrySizeWithItem, int firstEntryOff, int directCnt, int indirectCnt) { + return ITEMS_OFF + ITEM_SIZE * (directCnt + indirectCnt) <= firstEntryOff - newEntrySizeWithItem; + } + + /** + * @param buf Buffer. + * @param newEntrySizeWithItem New entry size as returned by {@link #getEntrySize(int, int)}. + * @return {@code true} If there is enough space for the entry. + */ + public boolean isEnoughSpace(ByteBuffer buf, int newEntrySizeWithItem) { + return isEnoughSpace(newEntrySizeWithItem, + getFirstEntryOffset(buf), getDirectCount(buf), getIndirectCount(buf)); } /** @@ -498,7 +515,7 @@ public class DataPageIO extends PageIO { * @param key Key. * @param val Value. * @param ver Version. - * @param entrySize Entry size as returned by {@link #getEntrySize(int, int)}. + * @param entrySizeWithItem Entry size as returned by {@link #getEntrySize(int, int)}. * @return Item ID. * @throws IgniteCheckedException If failed. */ @@ -508,29 +525,26 @@ public class DataPageIO extends PageIO { CacheObject key, CacheObject val, GridCacheVersion ver, - int entrySize + int entrySizeWithItem ) throws IgniteCheckedException { - if (entrySize > buf.capacity() - ITEMS_OFF) // TODO span multiple data pages with a single large entry + if (entrySizeWithItem > buf.capacity() - ITEMS_OFF) // TODO span multiple data pages with a single large entry throw new IgniteException("Too big entry: " + key + " " + val); int directCnt = getDirectCount(buf); int indirectCnt = getIndirectCount(buf); - int dataOff = getFirstEntryOffset(buf); - // Compact if we do not have enough space. - if (!enoughSpaceForEntry(entrySize, dataOff, directCnt, indirectCnt)) { + // Compact if we do not have enough space for entry. + if (!isEnoughSpace(entrySizeWithItem, dataOff, directCnt, indirectCnt)) { dataOff = compactDataEntries(buf, directCnt); -// assert enoughSpaceForEntry(entrySize, dataOff, directCnt, indirectCnt); - if (!enoughSpaceForEntry(entrySize, dataOff, directCnt, indirectCnt)) - return -1; // TODO replace with assert + assert isEnoughSpace(entrySizeWithItem, dataOff, directCnt, indirectCnt); } - // Attempt to write data right before the first entry. - dataOff -= entrySize - ITEM_SIZE; + // Write data right before the first entry. + dataOff -= entrySizeWithItem - ITEM_SIZE; - writeRowData(coctx, buf, dataOff, entrySize, key, val, ver); + writeRowData(coctx, buf, dataOff, entrySizeWithItem, key, val, ver); setFirstEntryOffset(buf, dataOff); @@ -538,6 +552,11 @@ public class DataPageIO extends PageIO { assert check(itemId): itemId; + // Update free space. If number of direct items did not change, then we were able to reuse item slot. + setFreeSpace(buf, getFreeSpace(buf) - entrySizeWithItem + (getDirectCount(buf) == directCnt ? ITEM_SIZE : 0)); + + assert getFreeSpace(buf) >= 0; + return (byte)itemId; } @@ -653,7 +672,7 @@ public class DataPageIO extends PageIO { * @param val Value. * @param ver Version. */ - public void writeRowData( + private void writeRowData( CacheObjectContext coctx, ByteBuffer buf, int dataOff, http://git-wip-us.apache.org/repos/asf/ignite/blob/e7d7e2cf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/util/PageHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/util/PageHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/util/PageHandler.java index 3d1b4e4..4e1ff0d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/util/PageHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/util/PageHandler.java @@ -85,7 +85,7 @@ public abstract class PageHandler<X> { public static <X> int writePage(Page page, PageHandler<X> h, X arg, int intArg, int dfltRes) throws IgniteCheckedException { if (page == null) - return dfltRes; + return dfltRes; // TODO drop dfltRes parameter and assert not null int res; @@ -94,7 +94,7 @@ public abstract class PageHandler<X> { ByteBuffer buf = page.getForWrite(); if (buf == null) - return dfltRes; + return dfltRes; // TODO ---//--- try { res = h.run(page, buf, arg, intArg);
