Search in sources :

Example 1 with PagesListNodeIO

use of org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO in project ignite by apache.

the class PagesList method put.

/**
 * @param bag Reuse bag.
 * @param dataId Data page ID.
 * @param dataPage Data page pointer.
 * @param dataAddr Data page address.
 * @param bucket Bucket.
 * @throws IgniteCheckedException If failed.
 */
protected final void put(ReuseBag bag, final long dataId, final long dataPage, final long dataAddr, int bucket) throws IgniteCheckedException {
    assert bag == null ^ dataAddr == 0L;
    for (int lockAttempt = 0; ; ) {
        Stripe stripe = getPageForPut(bucket, bag);
        // No need to continue if bag has been utilized at getPageForPut.
        if (bag != null && bag.isEmpty())
            return;
        final long tailId = stripe.tailId;
        final long tailPage = acquirePage(tailId);
        try {
            // Explicit check.
            long tailAddr = writeLockPage(tailId, tailPage, bucket, lockAttempt++, bag);
            if (tailAddr == 0L) {
                // No need to continue if bag has been utilized at writeLockPage.
                if (bag != null && bag.isEmpty())
                    return;
                else
                    continue;
            }
            assert PageIO.getPageId(tailAddr) == tailId : "pageId = " + PageIO.getPageId(tailAddr) + ", tailId = " + tailId;
            assert PageIO.getType(tailAddr) == PageIO.T_PAGE_LIST_NODE;
            boolean ok = false;
            try {
                PagesListNodeIO io = PageIO.getPageIO(tailAddr);
                ok = bag != null ? // Here we can always take pages from the bag to build our list.
                putReuseBag(tailId, tailPage, tailAddr, io, bag, bucket) : // the deadlock is impossible as well.
                putDataPage(tailId, tailPage, tailAddr, io, dataId, dataPage, dataAddr, bucket);
                if (ok) {
                    stripe.empty = false;
                    return;
                }
            } finally {
                writeUnlock(tailId, tailPage, tailAddr, ok);
            }
        } finally {
            releasePage(tailId, tailPage);
        }
    }
}
Also used : PagesListNodeIO(org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO)

Example 2 with PagesListNodeIO

use of org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO in project ignite by apache.

the class PagesList method doMerge.

/**
 * @param pageId Page ID.
 * @param page Page absolute pointer.
 * @param pageAddr Page address.
 * @param io IO.
 * @param nextId Next page ID.
 * @param nextPage Next page absolute pointer.
 * @param nextAddr Next page address.
 * @param bucket Bucket index.
 * @return Page to recycle.
 * @throws IgniteCheckedException If failed.
 */
private long doMerge(long pageId, long page, long pageAddr, PagesListNodeIO io, long nextId, long nextPage, long nextAddr, int bucket) throws IgniteCheckedException {
    long prevId = io.getPreviousId(pageAddr);
    if (nextId == 0L)
        return mergeNoNext(pageId, page, pageAddr, prevId, bucket);
    else {
        // No one must be able to merge it while we keep a reference.
        assert getPageId(nextAddr) == nextId;
        if (prevId == 0L) {
            // These references must be updated at the same time in write locks.
            assert PagesListNodeIO.VERSIONS.forPage(nextAddr).getPreviousId(nextAddr) == pageId;
            PagesListNodeIO nextIO = PagesListNodeIO.VERSIONS.forPage(nextAddr);
            nextIO.setPreviousId(nextAddr, 0);
            if (needWalDeltaRecord(nextId, nextPage, null))
                wal.log(new PagesListSetPreviousRecord(grpId, nextId, 0L));
        } else
            // Do a fair merge: link previous and next to each other.
            fairMerge(prevId, pageId, nextId, nextPage, nextAddr);
        return recyclePage(pageId, page, pageAddr, null);
    }
}
Also used : PagesListSetPreviousRecord(org.apache.ignite.internal.pagemem.wal.record.delta.PagesListSetPreviousRecord) PagesListNodeIO(org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO)

Example 3 with PagesListNodeIO

use of org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO in project ignite by apache.

the class PagesList method merge.

/**
 * @param pageId Page ID.
 * @param page Page pointer.
 * @param nextId Next page ID.
 * @param bucket Bucket index.
 * @return Page ID to recycle.
 * @throws IgniteCheckedException If failed.
 */
private long merge(final long pageId, final long page, long nextId, int bucket) throws IgniteCheckedException {
    // We should do mergeNoNext then.
    assert nextId != 0;
    // Lock all the pages in correct order (from next to previous) and do the merge in retry loop.
    for (; ; ) {
        final long curId = nextId;
        final long curPage = curId == 0L ? 0L : acquirePage(curId);
        try {
            boolean write = false;
            // Explicit check.
            final long curAddr = curPage == 0L ? 0L : writeLock(curId, curPage);
            // Explicit check.
            final long pageAddr = writeLock(pageId, page);
            if (pageAddr == 0L) {
                if (// Unlock next page if needed.
                curAddr != 0L)
                    writeUnlock(curId, curPage, curAddr, false);
                // Someone has merged or taken our empty page concurrently. Nothing to do here.
                return 0L;
            }
            try {
                PagesListNodeIO io = PagesListNodeIO.VERSIONS.forPage(pageAddr);
                if (!io.isEmpty(pageAddr))
                    // No need to merge anymore.
                    return 0L;
                // Check if we see a consistent state of the world.
                if (io.getNextId(pageAddr) == curId && (curId == 0L) == (curAddr == 0L)) {
                    long recycleId = doMerge(pageId, page, pageAddr, io, curId, curPage, curAddr, bucket);
                    write = true;
                    // Done.
                    return recycleId;
                }
                // Reread next page ID and go for retry.
                nextId = io.getNextId(pageAddr);
            } finally {
                if (curAddr != 0L)
                    writeUnlock(curId, curPage, curAddr, write);
                writeUnlock(pageId, page, pageAddr, write);
            }
        } finally {
            if (curPage != 0L)
                releasePage(curId, curPage);
        }
    }
}
Also used : PagesListNodeIO(org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO)

Example 4 with PagesListNodeIO

use of org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO in project ignite by apache.

the class PagesList method takeEmptyPage.

/**
 * @param bucket Bucket index.
 * @param initIoVers Optional IO to initialize page.
 * @return Removed page ID.
 * @throws IgniteCheckedException If failed.
 */
protected final long takeEmptyPage(int bucket, @Nullable IOVersions initIoVers) throws IgniteCheckedException {
    for (int lockAttempt = 0; ; ) {
        Stripe stripe = getPageForTake(bucket);
        if (stripe == null)
            return 0L;
        final long tailId = stripe.tailId;
        final long tailPage = acquirePage(tailId);
        try {
            // Explicit check.
            long tailAddr = writeLockPage(tailId, tailPage, bucket, lockAttempt++, null);
            if (tailAddr == 0L)
                continue;
            if (stripe.empty) {
                // Another thread took the last page.
                writeUnlock(tailId, tailPage, tailAddr, false);
                if (bucketsSize[bucket].get() > 0) {
                    // Ignore current attempt.
                    lockAttempt--;
                    continue;
                } else
                    return 0L;
            }
            assert PageIO.getPageId(tailAddr) == tailId : "tailId = " + tailId + ", tailPageId = " + PageIO.getPageId(tailAddr);
            assert PageIO.getType(tailAddr) == PageIO.T_PAGE_LIST_NODE;
            boolean dirty = false;
            long dataPageId;
            long recycleId = 0L;
            try {
                PagesListNodeIO io = PagesListNodeIO.VERSIONS.forPage(tailAddr);
                if (io.getNextId(tailAddr) != 0) {
                    // It is not a tail anymore, retry.
                    continue;
                }
                long pageId = io.takeAnyPage(tailAddr);
                if (pageId != 0L) {
                    decrementBucketSize(bucket);
                    if (needWalDeltaRecord(tailId, tailPage, null))
                        wal.log(new PagesListRemovePageRecord(grpId, tailId, pageId));
                    dirty = true;
                    dataPageId = pageId;
                    if (io.isEmpty(tailAddr)) {
                        long prevId = io.getPreviousId(tailAddr);
                        // to prevent empty page leak to data pages.
                        if (!isReuseBucket(bucket)) {
                            if (prevId != 0L) {
                                Boolean ok = write(prevId, cutTail, null, bucket, FALSE);
                                assert ok == TRUE : ok;
                                recycleId = recyclePage(tailId, tailPage, tailAddr, null);
                            } else
                                stripe.empty = true;
                        } else
                            stripe.empty = prevId == 0L;
                    }
                } else {
                    // a previous page, so, the current page can be collected
                    assert isReuseBucket(bucket);
                    long prevId = io.getPreviousId(tailAddr);
                    assert prevId != 0L;
                    Boolean ok = write(prevId, cutTail, bucket, FALSE);
                    assert ok == TRUE : ok;
                    decrementBucketSize(bucket);
                    if (initIoVers != null) {
                        dataPageId = PageIdUtils.changeType(tailId, FLAG_DATA);
                        PageIO initIo = initIoVers.latest();
                        initIo.initNewPage(tailAddr, dataPageId, pageSize());
                        if (needWalDeltaRecord(tailId, tailPage, null)) {
                            wal.log(new InitNewPageRecord(grpId, tailId, initIo.getType(), initIo.getVersion(), dataPageId));
                        }
                    } else
                        dataPageId = recyclePage(tailId, tailPage, tailAddr, null);
                    dirty = true;
                }
            // If we do not have a previous page (we are at head), then we still can return
            // current page but we have to drop the whole stripe. Since it is a reuse bucket,
            // we will not do that, but just return 0L, because this may produce contention on
            // meta page.
            } finally {
                writeUnlock(tailId, tailPage, tailAddr, dirty);
            }
            // Put recycled page (if any) to the reuse bucket after tail is unlocked.
            if (recycleId != 0L) {
                assert !isReuseBucket(bucket);
                reuseList.addForRecycle(new SingletonReuseBag(recycleId));
            }
            return dataPageId;
        } finally {
            releasePage(tailId, tailPage);
        }
    }
}
Also used : InitNewPageRecord(org.apache.ignite.internal.pagemem.wal.record.delta.InitNewPageRecord) PagesListInitNewPageRecord(org.apache.ignite.internal.pagemem.wal.record.delta.PagesListInitNewPageRecord) PagesListNodeIO(org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO) PagesListRemovePageRecord(org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord) PageIO(org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO) AbstractDataPageIO(org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO)

Example 5 with PagesListNodeIO

use of org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO in project ignite by apache.

the class PagesListInitNewPageRecord method applyDelta.

/**
 * {@inheritDoc}
 */
@Override
public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
    PagesListNodeIO io = PageIO.getPageIO(PageIO.T_PAGE_LIST_NODE, ioVer);
    PageMetrics metrics = pageMem.metrics().cacheGrpPageMetrics(groupId());
    io.initNewPage(pageAddr, pageId(), pageMem.realPageSize(groupId()), metrics);
    io.setPreviousId(pageAddr, prevPageId);
    if (addDataPageId != 0L) {
        int cnt = io.addPage(pageAddr, addDataPageId, pageMem.realPageSize(groupId()));
        assert cnt == 0 : cnt;
    }
}
Also used : PageMetrics(org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMetrics) PagesListNodeIO(org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO)

Aggregations

PagesListNodeIO (org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO)20 PagesListRemovePageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord)4 PagesListSetPreviousRecord (org.apache.ignite.internal.pagemem.wal.record.delta.PagesListSetPreviousRecord)4 AbstractDataPageIO (org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO)3 PageIO (org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO)3 DataPageSetFreeListPageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.DataPageSetFreeListPageRecord)2 PagesListSetNextRecord (org.apache.ignite.internal.pagemem.wal.record.delta.PagesListSetNextRecord)2 ByteBuffer (java.nio.ByteBuffer)1 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1 Map (java.util.Map)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1 IgniteCheckedException (org.apache.ignite.IgniteCheckedException)1 IgniteException (org.apache.ignite.IgniteException)1 InitNewPageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.InitNewPageRecord)1 PagesListInitNewPageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.PagesListInitNewPageRecord)1 PagesListMetaIO (org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListMetaIO)1 PageMetrics (org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMetrics)1 GridLongList (org.apache.ignite.internal.util.GridLongList)1