blob: c1eaa73230fcac42fb0020c4f88fc9e24f3a081a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.hadoop.hbase.procedure2.store;
import java.io.IOException;
import org.apache.hadoop.hbase.procedure2.Procedure;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability;
/**
* The ProcedureStore is used by the executor to persist the state of each procedure execution. This
* allows to resume the execution of pending/in-progress procedures in case of machine failure or
* service shutdown.
* <p/>
* Notice that, the implementation must guarantee that the maxProcId when loading is the maximum one
* in the whole history, not only the current live procedures. This is very important as for
* executing remote procedures, we have some nonce checks at region server side to prevent executing
* non-idempotent operations more than once. If the procedure id could go back, then we may
* accidentally ignore some important operations such as region assign or unassign.<br/>
* This may lead to some garbages so we provide a {@link #cleanup()} method, the framework will call
* this method periodically and the store implementation could do some clean up works in this
* method.
*/
@InterfaceAudience.Private
@InterfaceStability.Evolving
public interface ProcedureStore {
/**
* Store listener interface.
* <p/>
* The main process should register a listener and respond to the store events.
*/
public interface ProcedureStoreListener {
/**
* triggered when the store sync is completed.
*/
default void postSync() {
}
/**
* triggered when the store is not able to write out data. the main process should abort.
*/
default void abortProcess() {
}
/**
* Suggest that the upper layer should update the state of some procedures. Ignore this call
* will not effect correctness but performance.
* <p/>
* For a WAL based ProcedureStore implementation, if all the procedures stored in a WAL file
* have been deleted, or updated later in another WAL file, then we can delete the WAL file. If
* there are old procedures in a WAL file which are never deleted or updated, then we can not
* delete the WAL file and this will cause we hold lots of WAL file and slow down the master
* restarts. So here we introduce this method to tell the upper layer that please update the
* states of these procedures so that we can delete the old WAL file.
* @param procIds the id for the procedures
*/
default void forceUpdate(long[] procIds) {
}
}
/**
* An Iterator over a collection of Procedure
*/
public interface ProcedureIterator {
/**
* Reset the Iterator by seeking to the beginning of the list.
*/
void reset();
/**
* Returns true if the iterator has more elements.
* (In other words, returns true if next() would return a Procedure
* rather than throwing an exception.)
* @return true if the iterator has more procedures
*/
boolean hasNext();
/**
* Calling this method does not need to convert the protobuf message to the Procedure class, so
* if it returns true we can call {@link #skipNext()} to skip the procedure without
* deserializing. This could increase the performance.
* @return true if the iterator next element is a completed procedure.
*/
boolean isNextFinished();
/**
* Skip the next procedure
* <p/>
* This method is used to skip the deserializing of the procedure to increase performance, as
* when calling next we need to convert the protobuf message to the Procedure class.
*/
void skipNext();
/**
* Returns the next procedure in the iteration.
* @throws IOException if there was an error fetching/deserializing the procedure
* @return the next procedure in the iteration.
*/
@SuppressWarnings("rawtypes")
Procedure next() throws IOException;
}
/**
* Interface passed to the ProcedureStore.load() method to handle the store-load events.
*/
public interface ProcedureLoader {
/**
* Called by ProcedureStore.load() to notify about the maximum proc-id in the store.
* @param maxProcId the highest proc-id in the store
*/
void setMaxProcId(long maxProcId);
/**
* Called by the ProcedureStore.load() every time a set of procedures are ready to be executed.
* The ProcedureIterator passed to the method, has the procedure sorted in replay-order.
* @param procIter iterator over the procedures ready to be added to the executor.
*/
void load(ProcedureIterator procIter) throws IOException;
/**
* Called by the ProcedureStore.load() in case we have procedures not-ready to be added to
* the executor, which probably means they are corrupted since some information/link is missing.
* @param procIter iterator over the procedures not ready to be added to the executor, corrupted
*/
void handleCorrupted(ProcedureIterator procIter) throws IOException;
}
/**
* Add the listener to the notification list.
* @param listener The AssignmentListener to register
*/
void registerListener(ProcedureStoreListener listener);
/**
* Remove the listener from the notification list.
* @param listener The AssignmentListener to unregister
* @return true if the listner was in the list and it was removed, otherwise false.
*/
boolean unregisterListener(ProcedureStoreListener listener);
/**
* Start/Open the procedure store
* @param numThreads number of threads to be used by the procedure store
*/
void start(int numThreads) throws IOException;
/**
* Stop/Close the procedure store
* @param abort true if the stop is an abort
*/
void stop(boolean abort);
/**
* @return true if the store is running, otherwise false.
*/
boolean isRunning();
/**
* @return the number of threads/slots passed to start()
*/
int getNumThreads();
/**
* Set the number of procedure running.
* This can be used, for example, by the store to know how long to wait before a sync.
* @return how many procedures are running (may not be same as <code>count</code>).
*/
int setRunningProcedureCount(int count);
/**
* Acquire the lease for the procedure store.
* @deprecated since 2.3.0, will be removed in 4.0.0 along with
* {@link org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore}. As now we
* will store the procedure data in a master local region, and master itself will deal
* with the lease recovery of the region.
*/
@Deprecated
void recoverLease() throws IOException;
/**
* Load the Procedures in the store.
* @param loader the ProcedureLoader that will handle the store-load events
*/
void load(ProcedureLoader loader) throws IOException;
/**
* When a procedure is submitted to the executor insert(proc, null) will be called.
* 'proc' has a 'RUNNABLE' state and the initial information required to start up.
*
* When a procedure is executed and it returns children insert(proc, subprocs) will be called.
* 'proc' has a 'WAITING' state and an update state.
* 'subprocs' are the children in 'RUNNABLE' state with the initial information.
*
* @param proc the procedure to serialize and write to the store.
* @param subprocs the newly created child of the proc.
*/
void insert(Procedure<?> proc, Procedure<?>[] subprocs);
/**
* Serialize a set of new procedures.
* These procedures are freshly submitted to the executor and each procedure
* has a 'RUNNABLE' state and the initial information required to start up.
*
* @param procs the procedures to serialize and write to the store.
*/
void insert(Procedure<?>[] procs);
/**
* The specified procedure was executed,
* and the new state should be written to the store.
* @param proc the procedure to serialize and write to the store.
*/
void update(Procedure<?> proc);
/**
* The specified procId was removed from the executor,
* due to completion, abort or failure.
* The store implementor should remove all the information about the specified procId.
* @param procId the ID of the procedure to remove.
*/
void delete(long procId);
/**
* The parent procedure completed.
* Update the state and mark all the child deleted.
* @param parentProc the parent procedure to serialize and write to the store.
* @param subProcIds the IDs of the sub-procedure to remove.
*/
void delete(Procedure<?> parentProc, long[] subProcIds);
/**
* The specified procIds were removed from the executor,
* due to completion, abort or failure.
* The store implementor should remove all the information about the specified procIds.
* @param procIds the IDs of the procedures to remove.
* @param offset the array offset from where to start to delete
* @param count the number of IDs to delete
*/
void delete(long[] procIds, int offset, int count);
/**
* Will be called by the framework to give the store a chance to do some clean up works.
* <p/>
* Notice that this is for periodical clean up work, not for the clean up after close, if you want
* to close the store just call the {@link #stop(boolean)} method above.
*/
default void cleanup() {
}
}