public class EntryOperation extends KeyBasedMapOperation implements BackupAwareOperation, BlockingOperation, MutatingOperation
### Overview
Implementation of the the Offloadable contract for the EntryProcessor execution on a single key.
Allows off-loading the processing unit implementing this interface to the specified or default Executor. Currently supported in:
IMap.executeOnKey(Object, EntryProcessor) IMap.submitToKey(Object, EntryProcessor) IMap.submitToKey(Object, EntryProcessor, ExecutionCallback)
### Offloadable (for reading & writing)
If the EntryProcessor implements the Offloadable interface the processing will be offloaded to the given ExecutorService allowing unblocking the partition-thread. The key will be locked for the time-span of the processing in order to not generate a write-conflict.
If the EntryProcessor implements Offloadable the invocation scenario looks as follows: - EntryOperation fetches the entry and locks the given key on partition-thread - Then the processing is offloaded to the given executor - When the processing finishes if there is a change to the entry, a EntryOffloadableSetUnlockOperation is spawned which sets the new value and unlocks the given key on partition-thread if there is no change to the entry, a UnlockOperation is spawned, which just unlocks the kiven key on partition thread
There will not be a conflict on a write due to the pessimistic locking of the key. The threading looks as follows:
1. partition-thread (fetch & lock) 2. execution-thread (process) 3. partition-thread (set & unlock, or just unlock if no changes)
### Offloadable (for reading only)
If the EntryProcessor implements the Offloadable and ReadOnly interfaces the processing will be offloaded to the givenExecutorService allowing unblocking the partition-thread. Since the EntryProcessor is not supposed to do any changes to the Entry the key will NOT be locked for the time-span of the processing.
If the EntryProcessor implements Offloadable and ReadOnly the invocation scenario looks as follows: - EntryOperation fetches the entry and DOES NOT lock the given key on partition-thread - Then the processing is offloaded to the given executor - When the processing finishes if there is a change to the entry -> exception is thrown if there is no change to the entry -> the result is returned to the user from the executor-thread.
In the read-only case the threading looks as follows:
1. partition-thread (fetch) 2. execution-thread (process)
### Primary partition - main actors
- EntryOperation - EntryOffloadableSetUnlockOperation
### Backup partitions
Offloading will not be applied to backup partitions. It is possible to initialize the EntryBackupProcessor with some input provided by the EntryProcessor in the EntryProcessor.getBackupProcessor() method. The input allows providing context to the EntryBackupProcessor - for example the "delta" so that the EntryBackupProcessor does not have to calculate the "delta" but it may just apply it.
### Locking
The locking takes place only locally. If a partition locked by an off-loaded task gets migrated, the lock will not be migrated. In this situation the off-loaded task "relying" on the lock will fail on the unlock operation, since it will notice that there is no such a lock and therefore the processing for the key will get retried. The reason behind is that the off-loadable backup-processing does not use locking there cannot be any transfer of off-loadable locks from the primary replica to backup replicas.
GOTCHA: This operation LOADS missing keys from map-store, in contrast with PartitionWideEntryOperation.
dataKey, dataValue, maxIdle, threadId, ttl
createRecordStoreOnDemand, disableWanReplicationEvent, mapContainer, mapEventPublisher, mapService, mapServiceContext, recordStore
name
GENERIC_PARTITION_ID
Constructor and Description |
---|
EntryOperation() |
EntryOperation(String name,
Data dataKey,
EntryProcessor entryProcessor) |
Modifier and Type | Method and Description |
---|---|
CallStatus |
call()
Call the operation and returns the CallStatus.
|
int |
getAsyncBackupCount()
The asynchronous backup count.
|
Operation |
getBackupOperation()
Creates the
BackupOperation responsible for making the backup. |
int |
getId()
Returns type identifier for this class.
|
Object |
getResponse()
Called if and only if
Operation.returnsResponse() returned true ,
shortly after Operation.run() returns. |
int |
getSyncBackupCount()
The synchronous backup count.
|
WaitNotifyKey |
getWaitKey() |
void |
innerBeforeRun() |
void |
onWaitExpire() |
protected void |
readInternal(ObjectDataInput in) |
boolean |
shouldBackup()
Checks if a backup needs to be made.
|
boolean |
shouldWait() |
protected void |
writeInternal(ObjectDataOutput out) |
getKey, getThreadId, getTtl, getValue, setThreadId
beforeRun, canThisOpGenerateWANEvent, evict, getCallerProvenance, getFactoryId, getServiceName, getServiceNamespace, invalidateAllKeysInNearCaches, invalidateNearCache, invalidateNearCache, isPostProcessing, publishLoadAsWanUpdate, publishWanRemove, publishWanUpdate, setMapContainer, setMapService
getName, toString
afterRun, executedLocally, getCallerAddress, getCallerUuid, getCallId, getCallTimeout, getConnection, getInvocationTime, getLogger, getNodeEngine, getOperationResponseHandler, getPartitionId, getReplicaIndex, getService, getWaitTimeout, isUrgent, logError, onExecutionFailure, onInvocationException, onSetCallId, readData, requiresExplicitServiceName, returnsResponse, run, sendResponse, setCallerUuid, setNodeEngine, setOperationResponseHandler, setPartitionId, setReplicaIndex, setService, setServiceName, setValidateTarget, setWaitTimeout, toString, validatesTarget, writeData
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
getPartitionId
getWaitTimeout
readData, writeData
public EntryOperation()
public EntryOperation(String name, Data dataKey, EntryProcessor entryProcessor)
public void innerBeforeRun() throws Exception
innerBeforeRun
in class MapOperation
Exception
public CallStatus call()
Operation
Operation.run()
methods will be replaced by call
methods.
The call method looks very much like the Operation.run()
method and it is
very close to Runnable.run()
and Callable.call()
.
The main difference between a run and call, is that the returned
CallStatus from the call can tell something about the actual execution.
For example it could tell that some waiting is required in case of a
BlockingOperation
. Or that the actual execution work is
offloaded to some executor in case of an
Offloadable
EntryOperation
.
In the future new types of CallStatus are expected to be added, e.g. for
interleaving.
In the future it is very likely that for regular Operation that want to
return a concrete response, the actual response can be returned directly.
In this case we'll change the return type to Object
to prevent
forcing the response to be wrapped in a CallStatus.DONE_RESPONSE
monad since that would force additional litter to be created.call
in class Operation
Operation.run()
public WaitNotifyKey getWaitKey()
getWaitKey
in interface BlockingOperation
public boolean shouldWait()
shouldWait
in interface BlockingOperation
public void onWaitExpire()
onWaitExpire
in interface BlockingOperation
public Object getResponse()
Operation
Operation.returnsResponse()
returned true
,
shortly after Operation.run()
returns.getResponse
in class Operation
public Operation getBackupOperation()
BackupAwareOperation
BackupOperation
responsible for making the backup.getBackupOperation
in interface BackupAwareOperation
BackupOperation
responsible for making the backup.public boolean shouldBackup()
BackupAwareOperation
shouldBackup
in interface BackupAwareOperation
public int getAsyncBackupCount()
BackupAwareOperation
getAsyncBackupCount
in interface BackupAwareOperation
public int getSyncBackupCount()
BackupAwareOperation
getSyncBackupCount
in interface BackupAwareOperation
public int getId()
IdentifiedDataSerializable
getId
in interface IdentifiedDataSerializable
protected void readInternal(ObjectDataInput in) throws IOException
readInternal
in class KeyBasedMapOperation
IOException
protected void writeInternal(ObjectDataOutput out) throws IOException
writeInternal
in class KeyBasedMapOperation
IOException
Copyright © 2022 Hazelcast, Inc.. All Rights Reserved.