Search in sources :

Example 1 with MvccLinkAwareSearchRow

use of org.apache.ignite.internal.processors.cache.tree.mvcc.search.MvccLinkAwareSearchRow in project ignite by apache.

the class MvccUpdateDataRow method visit.

/**
 * {@inheritDoc}
 */
@Override
public int visit(BPlusTree<CacheSearchRow, CacheDataRow> tree, BPlusIO<CacheSearchRow> io, long pageAddr, int idx, IgniteWriteAheadLogManager wal) throws IgniteCheckedException {
    unsetFlags(DIRTY);
    RowLinkIO rowIo = (RowLinkIO) io;
    // Check if entry is locked on primary node.
    if (isFlagsSet(PRIMARY | FIRST)) {
        long lockCrd = rowIo.getMvccLockCoordinatorVersion(pageAddr, idx);
        long lockCntr = rowIo.getMvccLockCounter(pageAddr, idx);
        // We cannot continue while entry is locked by another transaction.
        if ((lockCrd != mvccCoordinatorVersion() || lockCntr != mvccCounter()) && isActive(cctx, lockCrd, lockCntr, mvccSnapshot)) {
            resCrd = lockCrd;
            resCntr = lockCntr;
            res = ResultType.LOCKED;
            return setFlags(STOP);
        }
    }
    MvccDataRow row = (MvccDataRow) tree.getRow(io, pageAddr, idx, RowData.LINK_WITH_HEADER);
    // In this case the row is already locked by current transaction and visible to it.
    if (isFlagsSet(FIRST)) {
        boolean removed = row.newMvccCoordinatorVersion() != MVCC_CRD_COUNTER_NA;
        long rowCrd, rowCntr;
        int rowOpCntr;
        if (removed) {
            rowCrd = row.newMvccCoordinatorVersion();
            rowCntr = row.newMvccCounter();
            rowOpCntr = row.newMvccOperationCounter();
        } else {
            rowCrd = row.mvccCoordinatorVersion();
            rowCntr = row.mvccCounter();
            rowOpCntr = row.mvccOperationCounter();
        }
        if (compare(mvccSnapshot, rowCrd, rowCntr) == 0) {
            res = mvccOperationCounter() == rowOpCntr ? ResultType.VERSION_FOUND : removed ? ResultType.PREV_NULL : ResultType.PREV_NOT_NULL;
            if (removed)
                setFlags(DELETED);
            else {
                // operation context is not available here and full row required if filter is set.
                if (res == ResultType.PREV_NOT_NULL && (isFlagsSet(NEED_PREV_VALUE) || filter != null)) {
                    oldRow = tree.getRow(io, pageAddr, idx, RowData.NO_KEY);
                    oldRow.key(key);
                } else
                    oldRow = row;
            }
            // See {@link org.apache.ignite.internal.processors.cache.CacheOperationFilter}.
            if (filter != null && !applyFilter(res == ResultType.PREV_NOT_NULL ? oldRow.value() : null))
                res = FILTERED;
            setFlags(LAST_COMMITTED_FOUND);
            // Copy new key flag from the previous row version if it was created by the current tx.
            if (isFlagsSet(PRIMARY))
                keyAbsentBeforeFlag(row.keyAbsentBeforeFlag());
        }
    }
    long rowLink = row.link();
    long rowCrd = row.mvccCoordinatorVersion();
    long rowCntr = row.mvccCounter();
    // with hint bits
    int rowOpCntr = row.mvccOperationCounter() | (row.mvccTxState() << MVCC_HINTS_BIT_OFF);
    long rowNewCrd = row.newMvccCoordinatorVersion();
    long rowNewCntr = row.newMvccCounter();
    // with hint bits
    int rowNewOpCntr = row.newMvccOperationCounter() | (row.newMvccTxState() << MVCC_HINTS_BIT_OFF);
    // Search for youngest committed by another transaction row.
    if (!isFlagsSet(LAST_COMMITTED_FOUND)) {
        if (!(resCrd == rowCrd && resCntr == rowCntr)) {
            // It's possible it is a chain of aborted changes
            byte txState = MvccUtils.state(cctx, rowCrd, rowCntr, rowOpCntr);
            if (txState == TxState.COMMITTED) {
                setFlags(LAST_COMMITTED_FOUND);
                if (rowNewCrd != MVCC_CRD_COUNTER_NA) {
                    if (rowNewCrd == rowCrd && rowNewCntr == rowCntr)
                        // Row was deleted by the same Tx it was created
                        txState = TxState.COMMITTED;
                    else if (rowNewCrd == resCrd && rowNewCntr == resCntr)
                        // The row is linked to the previously checked aborted version;
                        txState = TxState.ABORTED;
                    else
                        // Check with TxLog if removed version is committed;
                        txState = MvccUtils.state(cctx, rowNewCrd, rowNewCntr, rowNewOpCntr);
                    if (!(txState == TxState.COMMITTED || txState == TxState.ABORTED))
                        throw unexpectedStateException(cctx, txState, rowNewCrd, rowNewCntr, rowNewOpCntr, mvccSnapshot);
                    if (txState == TxState.COMMITTED)
                        setFlags(DELETED);
                }
                if (isFlagsSet(DELETED))
                    res = ResultType.PREV_NULL;
                else {
                    res = ResultType.PREV_NOT_NULL;
                    keyAbsentBeforeFlag(false);
                    // operation context is not available here and full row required if filter is set.
                    if ((isFlagsSet(NEED_PREV_VALUE) || isFlagsSet(NEED_OLD_VALUE) || filter != null)) {
                        oldRow = tree.getRow(io, pageAddr, idx, RowData.NO_KEY);
                        oldRow.key(key);
                    } else
                        oldRow = row;
                }
                if (isFlagsSet(CHECK_VERSION)) {
                    long crdVer, cntr;
                    int opCntr;
                    if (isFlagsSet(DELETED)) {
                        crdVer = rowNewCrd;
                        cntr = rowNewCntr;
                        opCntr = rowNewOpCntr;
                    } else {
                        crdVer = rowCrd;
                        cntr = rowCntr;
                        opCntr = rowOpCntr;
                    }
                    // If last committed row is not visible it is possible write conflict.
                    if (!isVisible(cctx, mvccSnapshot, crdVer, cntr, opCntr, false)) {
                        // or there is no visible version then there is no conflict.
                        if (isFlagsSet(FAST_UPDATE) && !(isFlagsSet(DELETED) && isVisible(cctx, mvccSnapshot, rowCrd, rowCntr, rowOpCntr, false))) {
                            res = ResultType.PREV_NULL;
                            setFlags(FAST_MISMATCH);
                        } else {
                            resCrd = crdVer;
                            resCntr = cntr;
                            // Write conflict.
                            res = ResultType.VERSION_MISMATCH;
                            return setFlags(STOP);
                        }
                    }
                }
                // See {@link org.apache.ignite.internal.processors.cache.CacheOperationFilter}.
                if (filter != null && !applyFilter(res == ResultType.PREV_NOT_NULL ? oldRow.value() : null))
                    res = FILTERED;
                // If invisible row is found for FAST_UPDATE case we should not lock row.
                if (!isFlagsSet(DELETED) && isFlagsSet(PRIMARY | REMOVE_OR_LOCK) && !isFlagsSet(FAST_MISMATCH)) {
                    rowIo.setMvccLockCoordinatorVersion(pageAddr, idx, mvccCoordinatorVersion());
                    rowIo.setMvccLockCounter(pageAddr, idx, mvccCounter());
                    // Actually, there is no need to log lock delta record into WAL.
                    setFlags(DIRTY);
                }
                // No need to acquire write locks anymore
                unsetFlags(CAN_WRITE);
            } else if (txState == TxState.ABORTED) {
                // save aborted version to fast check new version of next row
                resCrd = rowCrd;
                resCntr = rowCntr;
            } else
                throw unexpectedStateException(cctx, txState, rowCrd, rowCntr, rowOpCntr, mvccSnapshot);
        }
    } else // If we have not found any visible version then we does not see this row.
    if (isFlagsSet(FAST_MISMATCH)) {
        assert !isFlagsSet(CAN_CLEANUP);
        assert mvccVersionIsValid(rowNewCrd, rowNewCntr, rowNewOpCntr);
        // If we found visible removal version then we does not see this row.
        if (isVisible(cctx, mvccSnapshot, rowNewCrd, rowNewCntr, rowNewOpCntr, false))
            unsetFlags(FAST_MISMATCH);
        else // If the youngest visible for current transaction version is not removal version then it is write conflict.
        if (isVisible(cctx, mvccSnapshot, rowCrd, rowCntr, rowOpCntr, false)) {
            resCrd = rowCrd;
            resCntr = rowCntr;
            res = ResultType.VERSION_MISMATCH;
            return setFlags(STOP);
        }
    }
    long cleanupVer = mvccSnapshot.cleanupVersion();
    if (// Do not clean if cleanup version is not assigned.
    cleanupVer > MVCC_OP_COUNTER_NA && !isFlagsSet(CAN_CLEANUP) && isFlagsSet(LAST_COMMITTED_FOUND | DELETED)) {
        assert mvccVersionIsValid(rowNewCrd, rowNewCntr, rowNewOpCntr);
        // transaction and delete version is less or equal to cleanup one
        if (rowNewCrd < mvccCoordinatorVersion() || cleanupVer >= rowNewCntr)
            setFlags(CAN_CLEANUP);
    }
    if (isFlagsSet(CAN_CLEANUP) || !isFlagsSet(LAST_COMMITTED_FOUND)) {
        // can cleanup aborted versions
        if (cleanupRows == null)
            cleanupRows = new ArrayList<>();
        cleanupRows.add(new MvccLinkAwareSearchRow(cacheId, key, rowCrd, rowCntr, rowOpCntr & MVCC_OP_COUNTER_MASK, rowLink));
    } else {
        // Row obsoleted by current operation, all rows created or updated with current tx.
        if (isFlagsSet(NEED_HISTORY) && (row == oldRow || (rowCrd == mvccCoordinatorVersion() && rowCntr == mvccCounter()) || (rowNewCrd == mvccCoordinatorVersion() && rowNewCntr == mvccCounter()))) {
            if (histRows == null)
                histRows = new ArrayList<>();
            histRows.add(new MvccLinkAwareSearchRow(cacheId, key, rowCrd, rowCntr, rowOpCntr & MVCC_OP_COUNTER_MASK, rowLink));
        }
        if (// Do not clean if cleanup version is not assigned.
        cleanupVer > MVCC_OP_COUNTER_NA && !isFlagsSet(CAN_CLEANUP) && isFlagsSet(LAST_COMMITTED_FOUND) && (rowCrd < mvccCoordinatorVersion() || Long.compare(cleanupVer, rowCntr) >= 0))
            // all further versions are guaranteed to be less than cleanup version
            setFlags(CAN_CLEANUP);
    }
    return unsetFlags(FIRST);
}
Also used : RowLinkIO(org.apache.ignite.internal.processors.cache.tree.RowLinkIO) ArrayList(java.util.ArrayList) MvccLinkAwareSearchRow(org.apache.ignite.internal.processors.cache.tree.mvcc.search.MvccLinkAwareSearchRow)

Example 2 with MvccLinkAwareSearchRow

use of org.apache.ignite.internal.processors.cache.tree.mvcc.search.MvccLinkAwareSearchRow in project ignite by apache.

the class GridDhtTxAbstractEnlistFuture method fetchHistoryInfo.

/**
 * @param key Key.
 * @param hist History rows.
 * @return History entries.
 * @throws IgniteCheckedException, if failed.
 */
private CacheEntryInfoCollection fetchHistoryInfo(KeyCacheObject key, List<MvccLinkAwareSearchRow> hist) {
    List<GridCacheEntryInfo> res = new ArrayList<>();
    for (int i = 0; i < hist.size(); i++) {
        MvccLinkAwareSearchRow row0 = hist.get(i);
        MvccDataRow row = new MvccDataRow(cctx.group(), row0.hash(), row0.link(), key.partition(), CacheDataRowAdapter.RowData.NO_KEY_WITH_HINTS, row0.mvccCoordinatorVersion(), row0.mvccCounter(), row0.mvccOperationCounter(), false);
        GridCacheMvccEntryInfo entry = new GridCacheMvccEntryInfo();
        entry.cacheId(cctx.cacheId());
        entry.version(row.version());
        entry.value(row.value());
        entry.expireTime(row.expireTime());
        // Row should be retrieved with actual hints.
        entry.mvccVersion(row);
        entry.newMvccVersion(row);
        if (MvccUtils.compare(mvccSnapshot, row.mvccCoordinatorVersion(), row.mvccCounter()) != 0)
            entry.mvccTxState(row.mvccTxState());
        if (row.newMvccCoordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA && MvccUtils.compare(mvccSnapshot, row.newMvccCoordinatorVersion(), row.newMvccCounter()) != 0)
            entry.newMvccTxState(row.newMvccTxState());
        assert mvccSnapshot.coordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA;
        res.add(entry);
    }
    return new CacheEntryInfoCollection(res);
}
Also used : GridCacheEntryInfo(org.apache.ignite.internal.processors.cache.GridCacheEntryInfo) GridCacheMvccEntryInfo(org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo) CacheEntryInfoCollection(org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection) ArrayList(java.util.ArrayList) MvccDataRow(org.apache.ignite.internal.processors.cache.tree.mvcc.data.MvccDataRow) MvccLinkAwareSearchRow(org.apache.ignite.internal.processors.cache.tree.mvcc.search.MvccLinkAwareSearchRow)

Aggregations

ArrayList (java.util.ArrayList)2 MvccLinkAwareSearchRow (org.apache.ignite.internal.processors.cache.tree.mvcc.search.MvccLinkAwareSearchRow)2 CacheEntryInfoCollection (org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection)1 GridCacheEntryInfo (org.apache.ignite.internal.processors.cache.GridCacheEntryInfo)1 GridCacheMvccEntryInfo (org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo)1 RowLinkIO (org.apache.ignite.internal.processors.cache.tree.RowLinkIO)1 MvccDataRow (org.apache.ignite.internal.processors.cache.tree.mvcc.data.MvccDataRow)1