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);
}
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);
}
Aggregations