use of org.apache.ignite.internal.pagemem.wal.record.TxRecord in project ignite by apache.
the class IgniteWalSerializerVersionTest method testCheckDifferentSerializerVersionsAndLogTimestamp.
/**
* @throws Exception If failed.
*/
public void testCheckDifferentSerializerVersionsAndLogTimestamp() throws Exception {
IgniteCallable<List<WALRecord>> recordsFactory = new IgniteCallable<List<WALRecord>>() {
@Override
public List<WALRecord> call() throws Exception {
WALRecord rec0 = new DataRecord(Collections.<DataEntry>emptyList());
WALRecord rec1 = new TxRecord(PREPARED, null, null, null);
return Arrays.asList(rec0, rec1);
}
};
long time0 = U.currentTimeMillis();
check(new Checker(1, RecordV1Serializer.class, recordsFactory, Arrays.asList(0L, time0)));
long time1 = U.currentTimeMillis();
check(new Checker(2, RecordV2Serializer.class, recordsFactory, Arrays.asList(time1, time1)));
}
use of org.apache.ignite.internal.pagemem.wal.record.TxRecord in project ignite by apache.
the class IgniteWalReaderTest method iterateAndCountDataRecord.
/**
* Iterates over data records, checks each DataRecord and its entries, finds out all transactions in WAL.
*
* @param walIter iterator to use.
* @return count of data records observed for each global TX ID. Contains null for non tx updates.
* @throws IgniteCheckedException if failure.
*/
private Map<GridCacheVersion, Integer> iterateAndCountDataRecord(final WALIterator walIter, @Nullable final IgniteBiInClosure<Object, Object> cacheObjHnd, @Nullable final IgniteInClosure<DataRecord> dataRecordHnd) throws IgniteCheckedException {
final Map<GridCacheVersion, Integer> entriesUnderTxFound = new HashMap<>();
try (WALIterator stIt = walIter) {
while (stIt.hasNextX()) {
final IgniteBiTuple<WALPointer, WALRecord> next = stIt.nextX();
final WALRecord walRecord = next.get2();
if (walRecord.type() == WALRecord.RecordType.DATA_RECORD && walRecord instanceof DataRecord) {
final DataRecord dataRecord = (DataRecord) walRecord;
if (dataRecordHnd != null)
dataRecordHnd.apply(dataRecord);
final List<DataEntry> entries = dataRecord.writeEntries();
for (DataEntry entry : entries) {
final GridCacheVersion globalTxId = entry.nearXidVersion();
Object unwrappedKeyObj;
Object unwrappedValObj;
if (entry instanceof UnwrapDataEntry) {
UnwrapDataEntry unwrapDataEntry = (UnwrapDataEntry) entry;
unwrappedKeyObj = unwrapDataEntry.unwrappedKey();
unwrappedValObj = unwrapDataEntry.unwrappedValue();
} else if (entry instanceof LazyDataEntry) {
unwrappedKeyObj = null;
unwrappedValObj = null;
// can't check value
} else {
final CacheObject val = entry.value();
unwrappedValObj = val instanceof BinaryObject ? val : val.value(null, false);
final CacheObject key = entry.key();
unwrappedKeyObj = key instanceof BinaryObject ? key : key.value(null, false);
}
if (dumpRecords)
log.info("//Entry operation " + entry.op() + "; cache Id" + entry.cacheId() + "; " + "under transaction: " + globalTxId + // ; entry " + entry +
"; Key: " + unwrappedKeyObj + "; Value: " + unwrappedValObj);
if (cacheObjHnd != null && (unwrappedKeyObj != null || unwrappedValObj != null))
cacheObjHnd.apply(unwrappedKeyObj, unwrappedValObj);
final Integer entriesUnderTx = entriesUnderTxFound.get(globalTxId);
entriesUnderTxFound.put(globalTxId, entriesUnderTx == null ? 1 : entriesUnderTx + 1);
}
} else if (walRecord.type() == WALRecord.RecordType.TX_RECORD && walRecord instanceof TxRecord) {
final TxRecord txRecord = (TxRecord) walRecord;
final GridCacheVersion globalTxId = txRecord.nearXidVersion();
if (dumpRecords)
log.info("//Tx Record, state: " + txRecord.state() + "; nearTxVersion" + globalTxId);
}
}
}
return entriesUnderTxFound;
}
use of org.apache.ignite.internal.pagemem.wal.record.TxRecord in project ignite by apache.
the class TxRecordSerializer method read.
/**
* Reads {@link TxRecord} from given input.
*
* @param in Input
* @return TxRecord.
* @throws IOException In case of fail.
* @throws IgniteCheckedException In case of fail.
*/
public TxRecord read(ByteBufferBackedDataInput in) throws IOException, IgniteCheckedException {
byte txState = in.readByte();
TransactionState state = TransactionState.fromOrdinal(txState);
GridCacheVersion nearXidVer = RecordV1Serializer.readVersion(in, true);
GridCacheVersion writeVer = RecordV1Serializer.readVersion(in, true);
int participatingNodesSize = in.readInt();
Map<Short, Collection<Short>> participatingNodes = U.newHashMap(participatingNodesSize);
for (int i = 0; i < participatingNodesSize; i++) {
short primaryNode = in.readShort();
int backupNodesSize = in.readInt();
Collection<Short> backupNodes = new ArrayList<>(backupNodesSize);
for (int j = 0; j < backupNodesSize; j++) {
short backupNode = in.readShort();
backupNodes.add(backupNode);
}
participatingNodes.put(primaryNode, backupNodes);
}
long ts = in.readLong();
return new TxRecord(state, nearXidVer, writeVer, participatingNodes, ts);
}
use of org.apache.ignite.internal.pagemem.wal.record.TxRecord in project ignite by apache.
the class IgniteTxAdapter method state.
/**
* @param state State to set.
* @param timedOut Timeout flag.
* @return {@code True} if state changed.
*/
@SuppressWarnings({ "TooBroadScope" })
protected final boolean state(TransactionState state, boolean timedOut) {
boolean valid = false;
TransactionState prev;
boolean notify = false;
WALPointer ptr = null;
synchronized (this) {
prev = this.state;
switch(state) {
case ACTIVE:
{
valid = prev == SUSPENDED;
break;
}
case PREPARING:
{
valid = prev == ACTIVE;
break;
}
case PREPARED:
{
valid = prev == PREPARING;
break;
}
case COMMITTING:
{
valid = prev == PREPARED;
break;
}
case UNKNOWN:
{
if (setDone())
notify = true;
valid = prev == ROLLING_BACK || prev == COMMITTING;
break;
}
case COMMITTED:
{
if (setDone())
notify = true;
valid = prev == COMMITTING;
break;
}
case ROLLED_BACK:
{
if (setDone())
notify = true;
valid = prev == ROLLING_BACK;
break;
}
case MARKED_ROLLBACK:
{
valid = prev == ACTIVE || prev == PREPARING || prev == PREPARED || prev == SUSPENDED;
break;
}
case ROLLING_BACK:
{
valid = prev == ACTIVE || prev == MARKED_ROLLBACK || prev == PREPARING || prev == PREPARED || prev == SUSPENDED || (prev == COMMITTING && local() && !dht());
break;
}
case SUSPENDED:
{
valid = prev == ACTIVE;
break;
}
}
if (valid) {
this.state = state;
if (timedOut)
this.timedOut = true;
if (log.isDebugEnabled())
log.debug("Changed transaction state [prev=" + prev + ", new=" + this.state + ", tx=" + this + ']');
notifyAll();
} else {
if (log.isDebugEnabled())
log.debug("Invalid transaction state transition [invalid=" + state + ", cur=" + this.state + ", tx=" + this + ']');
}
if (valid) {
// Seal transactions maps.
if (state != ACTIVE && state != SUSPENDED)
seal();
if (cctx.wal() != null && cctx.tm().logTxRecords()) {
// Log tx state change to WAL.
if (state == PREPARED || state == COMMITTED || state == ROLLED_BACK) {
assert txNodes != null || state == ROLLED_BACK : "txNodes=" + txNodes + " state=" + state;
BaselineTopology baselineTop = cctx.kernalContext().state().clusterState().baselineTopology();
Map<Short, Collection<Short>> participatingNodes = consistentIdMapper.mapToCompactIds(topVer, txNodes, baselineTop);
TxRecord txRecord = new TxRecord(state, nearXidVersion(), writeVersion(), participatingNodes);
try {
ptr = cctx.wal().log(txRecord);
} catch (IgniteCheckedException e) {
U.error(log, "Failed to log TxRecord: " + txRecord, e);
throw new IgniteException("Failed to log TxRecord: " + txRecord, e);
}
}
}
}
}
if (valid) {
if (ptr != null && (state == COMMITTED || state == ROLLED_BACK))
try {
cctx.wal().fsync(ptr);
} catch (IgniteCheckedException e) {
String msg = "Failed to fsync ptr: " + ptr;
U.error(log, msg, e);
throw new IgniteException(msg, e);
}
}
if (notify) {
GridFutureAdapter<IgniteInternalTx> fut = finFut;
if (fut != null)
fut.onDone(this);
}
return valid;
}
use of org.apache.ignite.internal.pagemem.wal.record.TxRecord in project ignite by apache.
the class IgniteWalRecoveryTest method testTxRecordsConsistency.
/**
* Test that all DataRecord WAL records are within transaction boundaries - PREPARED and COMMITTED markers.
*
* @throws Exception If any fail.
*/
public void testTxRecordsConsistency() throws Exception {
System.setProperty(IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS, "true");
IgniteEx ignite = (IgniteEx) startGrids(3);
ignite.active(true);
try {
final String cacheName = "transactional";
CacheConfiguration<Object, Object> cacheConfiguration = new CacheConfiguration<>(cacheName).setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL).setAffinity(new RendezvousAffinityFunction(false, 32)).setCacheMode(CacheMode.PARTITIONED).setRebalanceMode(CacheRebalanceMode.SYNC).setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC).setBackups(0);
ignite.createCache(cacheConfiguration);
IgniteCache<Object, Object> cache = ignite.cache(cacheName);
GridCacheSharedContext<Object, Object> sharedCtx = ignite.context().cache().context();
GridCacheDatabaseSharedManager db = (GridCacheDatabaseSharedManager) sharedCtx.database();
db.waitForCheckpoint("test");
db.enableCheckpoints(false).get();
// Log something to know where to start.
WALPointer startPtr = sharedCtx.wal().log(new MemoryRecoveryRecord(U.currentTimeMillis()));
final int transactions = 100;
final int operationsPerTransaction = 40;
Random random = new Random();
for (int t = 1; t <= transactions; t++) {
Transaction tx = ignite.transactions().txStart(TransactionConcurrency.OPTIMISTIC, TransactionIsolation.READ_COMMITTED);
for (int op = 0; op < operationsPerTransaction; op++) {
int key = random.nextInt(1000) + 1;
Object value;
if (random.nextBoolean())
value = randomString(random) + key;
else
value = new BigObject(key);
cache.put(key, value);
}
if (random.nextBoolean()) {
tx.commit();
} else {
tx.rollback();
}
if (t % 50 == 0)
log.info("Finished transaction " + t);
}
Set<GridCacheVersion> activeTransactions = new HashSet<>();
// Check that all DataRecords are within PREPARED and COMMITTED tx records.
try (WALIterator it = sharedCtx.wal().replay(startPtr)) {
while (it.hasNext()) {
IgniteBiTuple<WALPointer, WALRecord> tup = it.next();
WALRecord rec = tup.get2();
if (rec instanceof TxRecord) {
TxRecord txRecord = (TxRecord) rec;
GridCacheVersion txId = txRecord.nearXidVersion();
switch(txRecord.state()) {
case PREPARED:
assert !activeTransactions.contains(txId) : "Transaction is already present " + txRecord;
activeTransactions.add(txId);
break;
case COMMITTED:
assert activeTransactions.contains(txId) : "No PREPARE marker for transaction " + txRecord;
activeTransactions.remove(txId);
break;
case ROLLED_BACK:
activeTransactions.remove(txId);
break;
default:
throw new IllegalStateException("Unknown Tx state of record " + txRecord);
}
} else if (rec instanceof DataRecord) {
DataRecord dataRecord = (DataRecord) rec;
for (DataEntry entry : dataRecord.writeEntries()) {
GridCacheVersion txId = entry.nearXidVersion();
assert activeTransactions.contains(txId) : "No transaction for entry " + entry;
}
}
}
}
} finally {
System.clearProperty(IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS);
stopAllGrids();
}
}
Aggregations