public void commit(Xid xid, boolean isOnePhase) throws XAException { // always call prepare() - even if this is just a 1PC! if (isOnePhase) prepare(xid); if (trace) log.trace("committing TransactionXaAdapter: " + globalTx); try { LocalTxInvocationContext ctx = icc.createTxInvocationContext(); ctx.setXaCache(this); if (configuration.isOnePhaseCommit()) { checkMarkedForRollback(); if (trace) log.trace("Doing an 1PC prepare call on the interceptor chain"); PrepareCommand command = commandsFactory.buildPrepareCommand(globalTx, modifications, true); try { invoker.invoke(ctx, command); } catch (Throwable e) { log.error("Error while processing 1PC PrepareCommand", e); throw new XAException(XAException.XAER_RMERR); } } else { CommitCommand commitCommand = commandsFactory.buildCommitCommand(globalTx); try { invoker.invoke(ctx, commitCommand); } catch (Throwable e) { log.error("Error while processing 1PC PrepareCommand", e); throw new XAException(XAException.XAER_RMERR); } } } finally { txTable.removeLocalTransaction(transaction); this.modifications = null; } }
private Object executeCommandAndCommitIfNeeded(InvocationContext ctx, VisitableCommand command) { final boolean txInjected = ctx.isInTxScope() && ((TxInvocationContext) ctx).isImplicitTransaction(); Object result; try { result = invoker.invoke(ctx, command); } catch (RuntimeException e) { if (txInjected) tryRollback(); throw e; } if (txInjected) { if (trace) log.tracef("Committing transaction as it was implicit: %s", getOngoingTransaction()); try { transactionManager.commit(); } catch (Throwable e) { log.couldNotCompleteInjectedTransaction(e); tryRollback(); throw new CacheException("Could not commit implicit transaction", e); } } return result; }
@SuppressWarnings("unchecked") final V get(Object key, EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { assertKeyNotNull(key); InvocationContext ctx = getInvocationContextForRead(null, explicitFlags, explicitClassLoader); GetKeyValueCommand command = commandsFactory.buildGetKeyValueCommand(key, ctx.getFlags()); return (V) invoker.invoke(ctx, command); }
private void applyStateInTransaction(XSiteState[] chunk) throws Exception { try { transactionManager.begin(); InvocationContext ctx = invocationContextFactory.createInvocationContext( transactionManager.getTransaction(), true); ((TxInvocationContext) ctx) .getCacheTransaction() .setStateTransferFlag(PUT_FOR_X_SITE_STATE_TRANSFER); for (XSiteState siteState : chunk) { interceptorChain.invoke(ctx, createPut(siteState)); if (trace) { log.tracef("Successfully applied key'%s'", siteState); } } transactionManager.commit(); if (debug) { log.debugf("Successfully applied state. %s keys inserted", chunk.length); } } catch (Exception e) { log.unableToApplyXSiteState(e); safeRollback(); throw e; } }
public static void replicateCommand(Cache cache, VisitableCommand command) throws Throwable { ComponentRegistry cr = extractComponentRegistry(cache); InterceptorChain ic = cr.getComponent(InterceptorChain.class); InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class); InvocationContext ctxt = icc.createInvocationContext(true, -1); ic.invoke(ctxt, command); }
final boolean containsKey( Object key, EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { assertKeyNotNull(key); InvocationContext ctx = getInvocationContextForRead(null, explicitFlags, explicitClassLoader); GetKeyValueCommand command = commandsFactory.buildGetKeyValueCommand(key, ctx.getFlags()); Object response = invoker.invoke(ctx, command); return response != null; }
boolean lock( Collection<? extends K> keys, EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { if (keys == null || keys.isEmpty()) { throw new IllegalArgumentException("Cannot lock empty list of keys"); } InvocationContext ctx = getInvocationContextForWrite(explicitFlags, explicitClassLoader); LockControlCommand command = commandsFactory.buildLockControlCommand(keys, false, ctx.getFlags()); return (Boolean) invoker.invoke(ctx, command); }
public void applyRemoteTxLog(List<WriteCommand> commands) { for (WriteCommand cmd : commands) { try { // this is a remotely originating tx cf.initializeReplicableCommand(cmd, true); InvocationContext ctx = icc.createInvocationContext(); ctx.setFlags(SKIP_REMOTE_LOOKUP, CACHE_MODE_LOCAL, SKIP_SHARED_CACHE_STORE, SKIP_LOCKING); interceptorChain.invoke(ctx, cmd); } catch (Exception e) { log.exceptionWhenReplaying(cmd, e); } } }
public void rollback(Xid xid) throws XAException { RollbackCommand rollbackCommand = commandsFactory.buildRollbackCommand(globalTx); LocalTxInvocationContext ctx = icc.createTxInvocationContext(); ctx.setXaCache(this); try { invoker.invoke(ctx, rollbackCommand); } catch (Throwable e) { log.error("Exception while rollback", e); throw new XAException(XAException.XA_HEURHAZ); } finally { txTable.removeLocalTransaction(transaction); this.modifications = null; } }
private void applyStateInNonTransaction(XSiteState[] chunk) { SingleKeyNonTxInvocationContext ctx = (SingleKeyNonTxInvocationContext) invocationContextFactory.createSingleKeyNonTxInvocationContext(); for (XSiteState siteState : chunk) { PutKeyValueCommand command = createPut(siteState); ctx.setLockOwner(command.getLockOwner()); interceptorChain.invoke(ctx, command); ctx.resetState(); // re-use same context. Old context is not longer needed if (trace) { log.tracef("Successfully applied key'%s'", siteState); } } if (debug) { log.debugf("Successfully applied state. %s keys inserted", chunk.length); } }
public int prepare(Xid xid) throws XAException { checkMarkedForRollback(); if (configuration.isOnePhaseCommit()) { if (trace) log.trace("Received prepare for tx: " + xid + " . Skipping call as 1PC will be used."); return XA_OK; } PrepareCommand prepareCommand = commandsFactory.buildPrepareCommand( globalTx, modifications, configuration.isOnePhaseCommit()); if (trace) log.trace("Sending prepare command through the chain: " + prepareCommand); LocalTxInvocationContext ctx = icc.createTxInvocationContext(); ctx.setXaCache(this); try { invoker.invoke(ctx, prepareCommand); return XA_OK; } catch (Throwable e) { log.error("Error while processing PrepareCommand", e); throw new XAException(XAException.XAER_RMERR); } }
private Map<Object, InternalCacheValue> applyStateMap( Map<Object, InternalCacheValue> state, boolean withRetry) { Map<Object, InternalCacheValue> retry = withRetry ? new HashMap<Object, InternalCacheValue>() : null; for (Map.Entry<Object, InternalCacheValue> e : state.entrySet()) { InternalCacheValue v = e.getValue(); InvocationContext ctx = icc.createInvocationContext(); // locking not necessary in the case of a join since the node isn't doing anything else // TODO what if the node is already running? ctx.setFlags( CACHE_MODE_LOCAL, SKIP_CACHE_LOAD, SKIP_REMOTE_LOOKUP, SKIP_SHARED_CACHE_STORE, SKIP_LOCKING, SKIP_OWNERSHIP_CHECK); try { PutKeyValueCommand put = cf.buildPutKeyValueCommand( e.getKey(), v.getValue(), v.getLifespan(), v.getMaxIdle(), ctx.getFlags()); interceptorChain.invoke(ctx, put); } catch (Exception ee) { if (withRetry) { if (trace) log.tracef( "Problem %s encountered when applying state for key %s. Adding entry to retry queue.", ee.getMessage(), e.getKey()); retry.put(e.getKey(), e.getValue()); } else { log.problemApplyingStateForKey(ee.getMessage(), e.getKey()); } } } return retry; }
final int size(EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { SizeCommand command = commandsFactory.buildSizeCommand(); return (Integer) invoker.invoke( getInvocationContextForRead(null, explicitFlags, explicitClassLoader), command); }
final void evict(K key, EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { assertKeyNotNull(key); InvocationContext ctx = createNonTxInvocationContext(explicitFlags, explicitClassLoader); EvictCommand command = commandsFactory.buildEvictCommand(key); invoker.invoke(ctx, command); }
@SuppressWarnings("unchecked") Set<Map.Entry<K, V>> entrySet(EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { InvocationContext ctx = getInvocationContextForRead(null, explicitFlags, explicitClassLoader); EntrySetCommand command = commandsFactory.buildEntrySetCommand(); return (Set<Map.Entry<K, V>>) invoker.invoke(ctx, command); }
@SuppressWarnings("unchecked") Collection<V> values(EnumSet<Flag> explicitFlags, ClassLoader explicitClassLoader) { InvocationContext ctx = getInvocationContextForRead(null, explicitFlags, explicitClassLoader); ValuesCommand command = commandsFactory.buildValuesCommand(); return (Collection<V>) invoker.invoke(ctx, command); }
private void doApplyState( Address sender, int segmentId, Collection<InternalCacheEntry> cacheEntries) { log.debugf( "Applying new state for segment %d of cache %s from node %s: received %d cache entries", segmentId, cacheName, sender, cacheEntries.size()); if (trace) { List<Object> keys = new ArrayList<Object>(cacheEntries.size()); for (InternalCacheEntry e : cacheEntries) { keys.add(e.getKey()); } log.tracef( "Received keys %s for segment %d of cache %s from node %s", keys, segmentId, cacheName, sender); } // CACHE_MODE_LOCAL avoids handling by StateTransferInterceptor and any potential locks in // StateTransferLock EnumSet<Flag> flags = EnumSet.of( PUT_FOR_STATE_TRANSFER, CACHE_MODE_LOCAL, IGNORE_RETURN_VALUES, SKIP_REMOTE_LOOKUP, SKIP_SHARED_CACHE_STORE, SKIP_OWNERSHIP_CHECK, SKIP_XSITE_BACKUP); for (InternalCacheEntry e : cacheEntries) { try { InvocationContext ctx; if (transactionManager != null) { // cache is transactional transactionManager.begin(); Transaction transaction = transactionManager.getTransaction(); ctx = icc.createInvocationContext(transaction); ((TxInvocationContext) ctx).setImplicitTransaction(true); } else { // non-tx cache ctx = icc.createSingleKeyNonTxInvocationContext(); } PutKeyValueCommand put = useVersionedPut ? commandsFactory.buildVersionedPutKeyValueCommand( e.getKey(), e.getValue(), e.getLifespan(), e.getMaxIdle(), e.getVersion(), flags) : commandsFactory.buildPutKeyValueCommand( e.getKey(), e.getValue(), e.getLifespan(), e.getMaxIdle(), flags); boolean success = false; try { interceptorChain.invoke(ctx, put); success = true; } finally { if (ctx.isInTxScope()) { if (success) { ((LocalTransaction) ((TxInvocationContext) ctx).getCacheTransaction()) .setFromStateTransfer(true); try { transactionManager.commit(); } catch (Throwable ex) { log.errorf( ex, "Could not commit transaction created by state transfer of key %s", e.getKey()); if (transactionManager.getTransaction() != null) { transactionManager.rollback(); } } } else { transactionManager.rollback(); } } } } catch (Exception ex) { log.problemApplyingStateForKey(ex.getMessage(), e.getKey(), ex); } } log.debugf("Finished applying state for segment %d of cache %s", segmentId, cacheName); }
private void invalidateSegments(Set<Integer> newSegments, Set<Integer> segmentsToL1) { // The actual owners keep track of the nodes that hold a key in L1 ("requestors") and // they invalidate the key on every requestor after a change. // But this information is only present on the owners where the ClusteredGetKeyValueCommand // got executed - if the requestor only contacted one owner, and that node is no longer an owner // (perhaps because it left the cluster), the other owners will not know to invalidate the key // on that requestor. Furthermore, the requestors list is not copied to the new owners during // state transfers. // To compensate for this, we delete all L1 entries in segments that changed ownership during // this topology update. We can't actually differentiate between L1 entries and regular entries, // so we delete all entries that don't belong to this node in the current OR previous topology. Set<Object> keysToL1 = new HashSet<Object>(); Set<Object> keysToRemove = new HashSet<Object>(); // gather all keys from data container that belong to the segments that are being removed/moved // to L1 for (InternalCacheEntry ice : dataContainer) { Object key = ice.getKey(); int keySegment = getSegment(key); if (segmentsToL1.contains(keySegment)) { keysToL1.add(key); } else if (!newSegments.contains(keySegment)) { keysToRemove.add(key); } } // gather all keys from cache store that belong to the segments that are being removed/moved to // L1 CacheStore cacheStore = getCacheStore(); if (cacheStore != null) { // todo [anistor] extend CacheStore interface to be able to specify a filter when loading keys // (ie. keys should belong to desired segments) try { Set<Object> storedKeys = cacheStore.loadAllKeys(new ReadOnlyDataContainerBackedKeySet(dataContainer)); for (Object key : storedKeys) { int keySegment = getSegment(key); if (segmentsToL1.contains(keySegment)) { keysToL1.add(key); } else if (!newSegments.contains(keySegment)) { keysToRemove.add(key); } } } catch (CacheLoaderException e) { log.failedLoadingKeysFromCacheStore(e); } } if (configuration.clustering().l1().onRehash()) { log.debugf("Moving to L1 state for segments %s of cache %s", segmentsToL1, cacheName); } else { log.debugf("Removing state for segments %s of cache %s", segmentsToL1, cacheName); } if (!keysToL1.isEmpty()) { try { InvalidateCommand invalidateCmd = commandsFactory.buildInvalidateFromL1Command( true, EnumSet.of(CACHE_MODE_LOCAL, SKIP_LOCKING), keysToL1); InvocationContext ctx = icc.createNonTxInvocationContext(); interceptorChain.invoke(ctx, invalidateCmd); log.debugf( "Invalidated %d keys, data container now has %d keys", keysToL1.size(), dataContainer.size()); if (trace) log.tracef("Invalidated keys: %s", keysToL1); } catch (CacheException e) { log.failedToInvalidateKeys(e); } } log.debugf( "Removing L1 state for segments not in %s or %s for cache %s", newSegments, segmentsToL1, cacheName); if (!keysToRemove.isEmpty()) { try { InvalidateCommand invalidateCmd = commandsFactory.buildInvalidateFromL1Command( false, EnumSet.of(CACHE_MODE_LOCAL, SKIP_LOCKING), keysToRemove); InvocationContext ctx = icc.createNonTxInvocationContext(); interceptorChain.invoke(ctx, invalidateCmd); log.debugf( "Invalidated %d keys, data container of cache %s now has %d keys", keysToRemove.size(), cacheName, dataContainer.size()); if (trace) log.tracef("Invalidated keys: %s", keysToRemove); } catch (CacheException e) { log.failedToInvalidateKeys(e); } } // todo [anistor] call CacheNotifier.notifyDataRehashed }