Search in sources :

Example 1 with PagesListRemovePageRecord

use of org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord in project ignite by apache.

the class PagesList method removeDataPage.

/**
     * @param dataId Data page ID.
     * @param dataPage Data page pointer.
     * @param dataAddr Data page address.
     * @param dataIO Data page IO.
     * @param bucket Bucket index.
     * @throws IgniteCheckedException If failed.
     * @return {@code True} if page was removed.
     */
protected final boolean removeDataPage(final long dataId, final long dataPage, final long dataAddr, DataPageIO dataIO, int bucket) throws IgniteCheckedException {
    final long pageId = dataIO.getFreeListPageId(dataAddr);
    assert pageId != 0;
    final long page = acquirePage(pageId);
    try {
        long nextId;
        long recycleId = 0L;
        // Explicit check.
        long pageAddr = writeLock(pageId, page);
        if (pageAddr == 0L)
            return false;
        boolean rmvd = false;
        try {
            PagesListNodeIO io = PagesListNodeIO.VERSIONS.forPage(pageAddr);
            rmvd = io.removePage(pageAddr, dataId);
            if (!rmvd)
                return false;
            bucketsSize[bucket].decrementAndGet();
            if (needWalDeltaRecord(pageId, page, null))
                wal.log(new PagesListRemovePageRecord(cacheId, pageId, dataId));
            // Reset free list page ID.
            dataIO.setFreeListPageId(dataAddr, 0L);
            if (needWalDeltaRecord(dataId, dataPage, null))
                wal.log(new DataPageSetFreeListPageRecord(cacheId, dataId, 0L));
            if (!io.isEmpty(pageAddr))
                // In optimistic case we still have something in the page and can leave it as is.
                return true;
            // If the page is empty, we have to try to drop it and link next and previous with each other.
            nextId = io.getNextId(pageAddr);
            // because if we will need to lock previous page, the locking order will be already correct.
            if (nextId == 0L) {
                long prevId = io.getPreviousId(pageAddr);
                recycleId = mergeNoNext(pageId, page, pageAddr, prevId, bucket);
            }
        } finally {
            writeUnlock(pageId, page, pageAddr, rmvd);
        }
        // Perform a fair merge after lock release (to have a correct locking order).
        if (nextId != 0L)
            recycleId = merge(pageId, page, nextId, bucket);
        if (recycleId != 0L)
            reuseList.addForRecycle(new SingletonReuseBag(recycleId));
        return true;
    } finally {
        releasePage(pageId, page);
    }
}
Also used : DataPageSetFreeListPageRecord(org.apache.ignite.internal.pagemem.wal.record.delta.DataPageSetFreeListPageRecord) PagesListNodeIO(org.apache.ignite.internal.processors.cache.database.freelist.io.PagesListNodeIO) PagesListRemovePageRecord(org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord)

Example 2 with PagesListRemovePageRecord

use of org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord 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++);
            if (tailAddr == 0L) {
                if (isReuseBucket(bucket) && lockAttempt == TRY_LOCK_ATTEMPTS)
                    addStripeForReuseBucket(bucket);
                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) {
                    bucketsSize[bucket].decrementAndGet();
                    if (needWalDeltaRecord(tailId, tailPage, null))
                        wal.log(new PagesListRemovePageRecord(cacheId, 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;
                    bucketsSize[bucket].decrementAndGet();
                    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(cacheId, 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.database.freelist.io.PagesListNodeIO) PagesListRemovePageRecord(org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord) DataPageIO(org.apache.ignite.internal.processors.cache.database.tree.io.DataPageIO) PageIO(org.apache.ignite.internal.processors.cache.database.tree.io.PageIO)

Aggregations

PagesListRemovePageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.PagesListRemovePageRecord)2 PagesListNodeIO (org.apache.ignite.internal.processors.cache.database.freelist.io.PagesListNodeIO)2 DataPageSetFreeListPageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.DataPageSetFreeListPageRecord)1 InitNewPageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.InitNewPageRecord)1 PagesListInitNewPageRecord (org.apache.ignite.internal.pagemem.wal.record.delta.PagesListInitNewPageRecord)1 DataPageIO (org.apache.ignite.internal.processors.cache.database.tree.io.DataPageIO)1 PageIO (org.apache.ignite.internal.processors.cache.database.tree.io.PageIO)1