use of javax.cache.processor.EntryProcessor in project ignite by apache.
the class GridCacheMapEntry method innerUpdate.
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public GridCacheUpdateAtomicResult innerUpdate(final GridCacheVersion newVer, final UUID evtNodeId, final UUID affNodeId, final GridCacheOperation op, @Nullable final Object writeObj, @Nullable final Object[] invokeArgs, final boolean writeThrough, final boolean readThrough, final boolean retval, final boolean keepBinary, @Nullable final IgniteCacheExpiryPolicy expiryPlc, final boolean evt, final boolean metrics, final boolean primary, final boolean verCheck, final AffinityTopologyVersion topVer, @Nullable final CacheEntryPredicate[] filter, final GridDrType drType, final long explicitTtl, final long explicitExpireTime, @Nullable final GridCacheVersion conflictVer, final boolean conflictResolve, final boolean intercept, @Nullable final UUID subjId, final String taskName, @Nullable final CacheObject prevVal, @Nullable final Long updateCntr, @Nullable final GridDhtAtomicAbstractUpdateFuture fut) throws IgniteCheckedException, GridCacheEntryRemovedException, GridClosureException {
assert cctx.atomic() && !detached();
AtomicCacheUpdateClosure c;
if (!primary && !isNear())
ensureFreeSpace();
synchronized (this) {
checkObsolete();
boolean internal = isInternal() || !context().userCache();
Map<UUID, CacheContinuousQueryListener> lsnrs = cctx.continuousQueries().updateListeners(internal, false);
boolean needVal = lsnrs != null || intercept || retval || op == GridCacheOperation.TRANSFORM || !F.isEmptyOrNulls(filter);
// Possibly read value from store.
boolean readFromStore = readThrough && needVal && (cctx.readThrough() && (op == GridCacheOperation.TRANSFORM || cctx.loadPreviousValue()));
c = new AtomicCacheUpdateClosure(this, newVer, op, writeObj, invokeArgs, readFromStore, writeThrough, keepBinary, expiryPlc, primary, verCheck, filter, explicitTtl, explicitExpireTime, conflictVer, conflictResolve, intercept, updateCntr);
key.valueBytes(cctx.cacheObjectContext());
if (isNear()) {
CacheDataRow dataRow = val != null ? new CacheDataRowAdapter(key, val, ver, expireTimeExtras()) : null;
c.call(dataRow);
} else
cctx.offheap().invoke(key, localPartition(), c);
GridCacheUpdateAtomicResult updateRes = c.updateRes;
assert updateRes != null : c;
CacheObject oldVal = c.oldRow != null ? c.oldRow.value() : null;
CacheObject updateVal = null;
GridCacheVersion updateVer = c.newVer;
// Apply metrics.
if (metrics && updateRes.outcome().updateReadMetrics() && cctx.cache().configuration().isStatisticsEnabled() && needVal) {
// PutIfAbsent methods must not update hit/miss statistics.
if (op != GridCacheOperation.UPDATE || F.isEmpty(filter) || !cctx.putIfAbsentFilter(filter))
cctx.cache().metrics0().onRead(oldVal != null);
}
switch(updateRes.outcome()) {
case VERSION_CHECK_FAILED:
{
if (!cctx.isNear()) {
CacheObject evtVal;
if (op == GridCacheOperation.TRANSFORM) {
EntryProcessor<Object, Object, ?> entryProcessor = (EntryProcessor<Object, Object, ?>) writeObj;
CacheInvokeEntry<Object, Object> entry = new CacheInvokeEntry<>(key, prevVal, version(), keepBinary, this);
try {
entryProcessor.process(entry, invokeArgs);
evtVal = entry.modified() ? cctx.toCacheObject(cctx.unwrapTemporary(entry.getValue())) : prevVal;
} catch (Exception ignore) {
evtVal = prevVal;
}
} else
evtVal = (CacheObject) writeObj;
long updateCntr0 = nextPartCounter();
if (updateCntr != null)
updateCntr0 = updateCntr;
onUpdateFinished(updateCntr0);
cctx.continuousQueries().onEntryUpdated(key, evtVal, prevVal, isInternal() || !context().userCache(), partition(), primary, false, updateCntr0, null, topVer);
}
return updateRes;
}
case CONFLICT_USE_OLD:
case FILTER_FAILED:
case INVOKE_NO_OP:
case INTERCEPTOR_CANCEL:
return updateRes;
}
assert updateRes.outcome() == UpdateOutcome.SUCCESS || updateRes.outcome() == UpdateOutcome.REMOVE_NO_VAL;
CacheObject evtOld = null;
if (evt && op == TRANSFORM && cctx.events().isRecordable(EVT_CACHE_OBJECT_READ)) {
assert writeObj instanceof EntryProcessor : writeObj;
evtOld = cctx.unwrapTemporary(oldVal);
Object transformClo = EntryProcessorResourceInjectorProxy.unwrap(writeObj);
cctx.events().addEvent(partition(), key, evtNodeId, null, newVer, EVT_CACHE_OBJECT_READ, evtOld, evtOld != null, evtOld, evtOld != null, subjId, transformClo.getClass().getName(), taskName, keepBinary);
}
if (c.op == GridCacheOperation.UPDATE) {
updateVal = val;
assert updateVal != null : c;
drReplicate(drType, updateVal, updateVer, topVer);
recordNodeId(affNodeId, topVer);
if (evt && cctx.events().isRecordable(EVT_CACHE_OBJECT_PUT)) {
if (evtOld == null)
evtOld = cctx.unwrapTemporary(oldVal);
cctx.events().addEvent(partition(), key, evtNodeId, null, newVer, EVT_CACHE_OBJECT_PUT, updateVal, true, evtOld, evtOld != null, subjId, null, taskName, keepBinary);
}
} else {
assert c.op == GridCacheOperation.DELETE : c.op;
clearReaders();
drReplicate(drType, null, newVer, topVer);
recordNodeId(affNodeId, topVer);
if (evt && cctx.events().isRecordable(EVT_CACHE_OBJECT_REMOVED)) {
if (evtOld == null)
evtOld = cctx.unwrapTemporary(oldVal);
cctx.events().addEvent(partition(), key, evtNodeId, null, newVer, EVT_CACHE_OBJECT_REMOVED, null, false, evtOld, evtOld != null, subjId, null, taskName, keepBinary);
}
}
if (updateRes.success())
updateMetrics(c.op, metrics);
// Continuous query filter should be perform under lock.
if (lsnrs != null) {
CacheObject evtVal = cctx.unwrapTemporary(updateVal);
CacheObject evtOldVal = cctx.unwrapTemporary(oldVal);
cctx.continuousQueries().onEntryUpdated(lsnrs, key, evtVal, evtOldVal, internal, partition(), primary, false, c.updateRes.updateCounter(), fut, topVer);
}
cctx.dataStructures().onEntryUpdated(key, c.op == GridCacheOperation.DELETE, keepBinary);
if (intercept) {
if (c.op == GridCacheOperation.UPDATE) {
cctx.config().getInterceptor().onAfterPut(new CacheLazyEntry(cctx, key, null, updateVal, null, keepBinary, c.updateRes.updateCounter()));
} else {
assert c.op == GridCacheOperation.DELETE : c.op;
cctx.config().getInterceptor().onAfterRemove(new CacheLazyEntry(cctx, key, null, oldVal, null, keepBinary, c.updateRes.updateCounter()));
}
}
}
onUpdateFinished(c.updateRes.updateCounter());
return c.updateRes;
}
use of javax.cache.processor.EntryProcessor in project ignite by apache.
the class GridLocalAtomicCache method invokeAll.
/** {@inheritDoc} */
@Override
public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor, Object... args) throws IgniteCheckedException {
A.notNull(keys, "keys", entryProcessor, "entryProcessor");
if (keyCheck)
validateCacheKeys(keys);
Map<? extends K, EntryProcessor> invokeMap = F.viewAsMap(keys, new C1<K, EntryProcessor>() {
@Override
public EntryProcessor apply(K k) {
return entryProcessor;
}
});
CacheOperationContext opCtx = ctx.operationContextPerCall();
final boolean keepBinary = opCtx != null && opCtx.isKeepBinary();
return (Map<K, EntryProcessorResult<T>>) updateAllInternal(TRANSFORM, invokeMap.keySet(), invokeMap.values(), args, expiryPerCall(), false, false, null, ctx.writeThrough(), ctx.readThrough(), keepBinary);
}
use of javax.cache.processor.EntryProcessor in project ignite by apache.
the class GridLocalAtomicCache method updateWithBatch.
/**
* Updates entries using batched write-through.
*
* @param op Operation.
* @param keys Keys.
* @param vals Values.
* @param invokeArgs Optional arguments for EntryProcessor.
* @param expiryPlc Expiry policy.
* @param ver Cache version.
* @param filter Optional filter.
* @param subjId Subject ID.
* @param taskName Task name.
* @return Results map for invoke operation.
* @throws CachePartialUpdateCheckedException If update failed.
*/
@SuppressWarnings({ "ForLoopReplaceableByForEach", "unchecked" })
private Map<K, EntryProcessorResult> updateWithBatch(GridCacheOperation op, Collection<? extends K> keys, @Nullable Iterable<?> vals, @Nullable Object[] invokeArgs, @Nullable ExpiryPolicy expiryPlc, GridCacheVersion ver, @Nullable CacheEntryPredicate[] filter, boolean keepBinary, UUID subjId, String taskName) throws IgniteCheckedException {
List<GridCacheEntryEx> locked = lockEntries(keys);
try {
int size = locked.size();
Map<KeyCacheObject, CacheObject> putMap = null;
Collection<KeyCacheObject> rmvKeys = null;
List<CacheObject> writeVals = null;
Map<K, EntryProcessorResult> invokeResMap = op == TRANSFORM ? U.<K, EntryProcessorResult>newHashMap(size) : null;
List<GridCacheEntryEx> filtered = new ArrayList<>(size);
CachePartialUpdateCheckedException err = null;
Iterator<?> valsIter = vals != null ? vals.iterator() : null;
boolean intercept = ctx.config().getInterceptor() != null;
for (int i = 0; i < size; i++) {
GridCacheEntryEx entry = locked.get(i);
Object val = valsIter != null ? valsIter.next() : null;
if (val == null && op != DELETE)
throw new NullPointerException("Null value.");
try {
try {
if (!ctx.isAllLocked(entry, filter)) {
if (log.isDebugEnabled())
log.debug("Entry did not pass the filter (will skip write) [entry=" + entry + ", filter=" + Arrays.toString(filter) + ']');
continue;
}
} catch (IgniteCheckedException e) {
if (err == null)
err = partialUpdateException();
err.add(F.asList(entry.key()), e);
continue;
}
if (op == TRANSFORM) {
ctx.kernalContext().resource().inject(val, GridResourceIoc.AnnotationSet.ENTRY_PROCESSOR, ctx.name());
EntryProcessor<Object, Object, Object> entryProcessor = (EntryProcessor<Object, Object, Object>) val;
CacheObject old = entry.innerGet(null, null, /*read-through*/
true, /*update-metrics*/
true, /*event*/
true, subjId, entryProcessor, taskName, null, keepBinary);
Object oldVal = null;
CacheInvokeEntry<Object, Object> invokeEntry = new CacheInvokeEntry<>(entry.key(), old, entry.version(), keepBinary, entry);
CacheObject updated;
Object updatedVal = null;
CacheInvokeResult invokeRes = null;
try {
Object computed = entryProcessor.process(invokeEntry, invokeArgs);
updatedVal = ctx.unwrapTemporary(invokeEntry.getValue());
updated = ctx.toCacheObject(updatedVal);
if (computed != null)
invokeRes = CacheInvokeResult.fromResult(ctx.unwrapTemporary(computed));
} catch (Exception e) {
invokeRes = CacheInvokeResult.fromError(e);
updated = old;
}
if (invokeRes != null)
invokeResMap.put((K) entry.key().value(ctx.cacheObjectContext(), false), invokeRes);
if (updated == null) {
if (intercept) {
IgniteBiTuple<Boolean, ?> interceptorRes = ctx.config().getInterceptor().onBeforeRemove(new CacheLazyEntry(ctx, entry.key(), invokeEntry.key(), old, oldVal, keepBinary));
if (ctx.cancelRemove(interceptorRes))
continue;
}
// Update previous batch.
if (putMap != null) {
err = updatePartialBatch(filtered, ver, writeVals, putMap, null, expiryPlc, keepBinary, err, subjId, taskName);
putMap = null;
writeVals = null;
filtered = new ArrayList<>();
}
// Start collecting new batch.
if (rmvKeys == null)
rmvKeys = new ArrayList<>(size);
rmvKeys.add(entry.key());
} else {
if (intercept) {
Object interceptorVal = ctx.config().getInterceptor().onBeforePut(new CacheLazyEntry(ctx, entry.key(), invokeEntry.getKey(), old, oldVal, keepBinary), updatedVal);
if (interceptorVal == null)
continue;
updated = ctx.toCacheObject(ctx.unwrapTemporary(interceptorVal));
}
// Update previous batch.
if (rmvKeys != null) {
err = updatePartialBatch(filtered, ver, null, null, rmvKeys, expiryPlc, keepBinary, err, subjId, taskName);
rmvKeys = null;
filtered = new ArrayList<>();
}
if (putMap == null) {
putMap = new LinkedHashMap<>(size, 1.0f);
writeVals = new ArrayList<>(size);
}
putMap.put(entry.key(), updated);
writeVals.add(updated);
}
} else if (op == UPDATE) {
CacheObject cacheVal = ctx.toCacheObject(val);
if (intercept) {
CacheObject old = entry.innerGet(null, null, /*read-through*/
ctx.loadPreviousValue(), /**update-metrics*/
true, /**event*/
true, subjId, null, taskName, null, keepBinary);
Object interceptorVal = ctx.config().getInterceptor().onBeforePut(new CacheLazyEntry(ctx, entry.key(), old, keepBinary), val);
if (interceptorVal == null)
continue;
cacheVal = ctx.toCacheObject(ctx.unwrapTemporary(interceptorVal));
}
if (putMap == null) {
putMap = new LinkedHashMap<>(size, 1.0f);
writeVals = new ArrayList<>(size);
}
putMap.put(entry.key(), cacheVal);
writeVals.add(cacheVal);
} else {
assert op == DELETE;
if (intercept) {
CacheObject old = entry.innerGet(null, null, /*read-through*/
ctx.loadPreviousValue(), /**update-metrics*/
true, /**event*/
true, subjId, null, taskName, null, keepBinary);
IgniteBiTuple<Boolean, ?> interceptorRes = ctx.config().getInterceptor().onBeforeRemove(new CacheLazyEntry(ctx, entry.key(), old, keepBinary));
if (ctx.cancelRemove(interceptorRes))
continue;
}
if (rmvKeys == null)
rmvKeys = new ArrayList<>(size);
rmvKeys.add(entry.key());
}
filtered.add(entry);
} catch (IgniteCheckedException e) {
if (err == null)
err = partialUpdateException();
err.add(F.asList(entry.key()), e);
} catch (GridCacheEntryRemovedException ignore) {
assert false : "Entry cannot become obsolete while holding lock.";
}
}
// Store final batch.
if (putMap != null || rmvKeys != null) {
err = updatePartialBatch(filtered, ver, writeVals, putMap, rmvKeys, expiryPlc, keepBinary, err, subjId, taskName);
} else
assert filtered.isEmpty();
if (err != null)
throw err;
return invokeResMap;
} finally {
unlockEntries(locked);
}
}
use of javax.cache.processor.EntryProcessor in project ignite by apache.
the class IgniteConcurrentEntryProcessorAccessStopTest method testConcurrentAccess.
/**
* Tests concurrent instance shutdown.
*
* @throws Exception If failed.
*/
public void testConcurrentAccess() throws Exception {
CacheConfiguration<Object, Object> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
Ignite ignite = grid();
final IgniteCache<Object, Object> dfltCache = ignite.getOrCreateCache(ccfg);
dfltCache.put("1", "1");
Thread invoker = new Thread(new Runnable() {
@Override
public void run() {
dfltCache.invoke("1", new EntryProcessor<Object, Object, Object>() {
@Override
public Object process(MutableEntry<Object, Object> e, Object... args) {
int i = 100_000;
while (i-- >= 0) grid().cluster().nodes();
e.remove();
return null;
}
});
}
});
invoker.setName("ConcurrentEntryProcessorActionThread");
invoker.start();
stopGrid();
invoker.join();
}
use of javax.cache.processor.EntryProcessor in project ignite by apache.
the class IgniteTxAdapter method applyTransformClosures.
/**
* @param txEntry Entry to process.
* @param metrics {@code True} if metrics should be updated.
* @param ret Optional return value to initialize.
* @return Tuple containing transformation results.
* @throws IgniteCheckedException If failed to get previous value for transform.
* @throws GridCacheEntryRemovedException If entry was concurrently deleted.
*/
protected IgniteBiTuple<GridCacheOperation, CacheObject> applyTransformClosures(IgniteTxEntry txEntry, boolean metrics, @Nullable GridCacheReturn ret) throws GridCacheEntryRemovedException, IgniteCheckedException {
assert txEntry.op() != TRANSFORM || !F.isEmpty(txEntry.entryProcessors()) : txEntry;
GridCacheContext cacheCtx = txEntry.context();
assert cacheCtx != null;
if (isSystemInvalidate())
return F.t(cacheCtx.writeThrough() ? RELOAD : DELETE, null);
if (F.isEmpty(txEntry.entryProcessors())) {
if (ret != null)
ret.value(cacheCtx, txEntry.value(), txEntry.keepBinary());
return F.t(txEntry.op(), txEntry.value());
} else {
T2<GridCacheOperation, CacheObject> calcVal = txEntry.entryProcessorCalculatedValue();
if (calcVal != null)
return calcVal;
boolean recordEvt = cctx.gridEvents().isRecordable(EVT_CACHE_OBJECT_READ);
final boolean keepBinary = txEntry.keepBinary();
CacheObject cacheVal;
if (txEntry.hasValue())
cacheVal = txEntry.value();
else if (txEntry.hasOldValue())
cacheVal = txEntry.oldValue();
else {
cacheVal = txEntry.cached().innerGet(null, this, /*read through*/
false, /*metrics*/
metrics, /*event*/
recordEvt, /*subjId*/
subjId, /*closure name */
recordEvt ? F.first(txEntry.entryProcessors()).get1() : null, resolveTaskName(), null, keepBinary);
}
boolean modified = false;
Object val = null;
Object key = null;
GridCacheVersion ver;
try {
ver = txEntry.cached().version();
} catch (GridCacheEntryRemovedException e) {
assert optimistic() : txEntry;
if (log.isDebugEnabled())
log.debug("Failed to get entry version: [msg=" + e.getMessage() + ']');
ver = null;
}
for (T2<EntryProcessor<Object, Object, Object>, Object[]> t : txEntry.entryProcessors()) {
CacheInvokeEntry<Object, Object> invokeEntry = new CacheInvokeEntry<>(txEntry.key(), key, cacheVal, val, ver, keepBinary, txEntry.cached());
Object procRes = null;
Exception err = null;
try {
EntryProcessor<Object, Object, Object> processor = t.get1();
procRes = processor.process(invokeEntry, t.get2());
val = invokeEntry.getValue();
key = invokeEntry.key();
} catch (Exception e) {
err = e;
}
if (ret != null) {
if (err != null || procRes != null)
ret.addEntryProcessResult(txEntry.context(), txEntry.key(), null, procRes, err, keepBinary);
else
ret.invokeResult(true);
}
modified |= invokeEntry.modified();
}
if (modified)
cacheVal = cacheCtx.toCacheObject(cacheCtx.unwrapTemporary(val));
GridCacheOperation op = modified ? (val == null ? DELETE : UPDATE) : NOOP;
if (op == NOOP) {
ExpiryPolicy expiry = cacheCtx.expiryForTxEntry(txEntry);
if (expiry != null) {
long ttl = CU.toTtl(expiry.getExpiryForAccess());
txEntry.ttl(ttl);
if (ttl == CU.TTL_ZERO)
op = DELETE;
}
}
return F.t(op, cacheVal);
}
}
Aggregations