
com.hazelcast.spi.impl.operationexecutor.OperationRunner Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.spi.impl.operationexecutor;
import com.hazelcast.nio.Packet;
import com.hazelcast.spi.Operation;
/**
* The OperationRunner is responsible for the actual running of operations.
*
* So the {@link OperationExecutor} is responsible for 'executing' them (so finding a thread to run on), the actual work is done
* by the {@link OperationRunner}. This separation of concerns makes the code a lot simpler and makes it possible to swap parts
* of the system.
*
* Since HZ 3.5 there are multiple OperationRunner instances; each partition will have its own OperationRunner, but also
* generic threads will have their own OperationRunners. Each OperationRunner exposes the Operation it is currently working
* on and this makes it possible to hook on all kinds of additional functionality like detecting slow operations, sampling which
* operations are executed most frequently, check if an operation is still running, etc etc.
*/
public abstract class OperationRunner {
protected final int partitionId;
protected volatile Object currentTask;
private volatile Thread currentThread;
public OperationRunner(int partitionId) {
this.partitionId = partitionId;
}
public abstract void run(Packet packet) throws Exception;
public abstract void run(Runnable task);
public abstract void run(Operation task);
/**
* Returns the current task that is executing. This value could be null if no operation is executing.
*
* Value could be stale as soon as it is returned.
*
* This method is thread-safe; so the thread that executes a task will set/unset the current task,
* any other thread in the system is allowed to read it.
*
* @return the current running task.
*/
public final Object currentTask() {
return currentTask;
}
/**
* Sets the thread that is running this OperationRunner instance.
*
* This method should only be called from the {@link OperationExecutor} since this component is responsible for
* executing operations on an OperationRunner.
*
* @param currentThread the current Thread. Can be called with 'null', clearing the currentThread field.
*/
public final void setCurrentThread(Thread currentThread) {
this.currentThread = currentThread;
}
/**
* Get the thread that is currently running this OperationRunner instance.
*
* This value only has meaning when an Operation is running. It depends on the implementation if the field is unset
* after an operation is executed or not. So it could be that a value is returned while no operation is running.
*
* For example, the {@link com.hazelcast.spi.impl.operationexecutor.classic.ClassicOperationExecutor} will never unset
* this field since each OperationRunner is bound to a single OperationThread; so this field is initialized when the
* OperationRunner is created.
*
* The returned value could be null. When it is null, currently no thread is running this OperationRunner.
*
* Recommended idiom for slow operation detection:
* 1: First read the operation and store the reference.
* 2: Then read the current thread and store the reference
* 3: Later read the operation again. If the operation-instance is the same, it means that you have captured the right thread.
*
* Then you use this Thread to create a stack trace. It can happen that the stracktrace doesn't reflect the call-state the
* thread had when the slow operation was detected. This could be solved by rechecking the currentTask after you have detected
* the slow operation. BUt don't create a stacktrace before you do the first recheck of the operation because otherwise it
* will cause a lot of overhead.
*
* @return the Thread that currently is running this OperationRunner instance.
*/
public final Thread currentThread() {
return currentThread;
}
/**
* Returns the partitionId this OperationRunner is responsible for. If the partition id is smaller than 0,
* it is either a generic or ad hoc OperationRunner.
*
* The value will never change for this OperationRunner instance.
*
* @return the partition id.
*/
public final int getPartitionId() {
return partitionId;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy