org.apache.flume.channel.BasicTransactionSemantics Maven / Gradle / Ivy
/*
* 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.flume.channel;
import org.apache.flume.Channel;
import org.apache.flume.ChannelException;
import org.apache.flume.Event;
import org.apache.flume.Transaction;
import com.google.common.base.Preconditions;
/**
*
* An implementation of basic {@link Transaction} semantics designed
* to work in concert with {@link BasicChannelSemantics} to simplify
* creation of robust {@link Channel} implementations. This class
* ensures that each transaction implementation method is called only
* while the transaction is in the correct state for that method, and
* only by the thread that created the transaction. Nested calls to
* begin()
and close()
are supported as long
* as they are balanced.
*
*
* Subclasses need only implement doPut
,
* doTake
, doCommit
, and
* doRollback
, and the developer can rest assured that
* those methods are called only after transaction state preconditions
* have been properly met. doBegin
and
* doClose
may also be implemented if there is work to be
* done at those points.
*
*
* All InterruptedException exceptions thrown from the implementations
* of the doXXX
methods are automatically wrapped to
* become ChannelExceptions, but only after restoring the interrupted
* status of the thread so that any subsequent blocking method calls
* will themselves throw InterruptedException rather than blocking.
* The exception to this rule is doTake
, which simply
* returns null instead of wrapping and propagating the
* InterruptedException, though it still first restores the
* interrupted status of the thread.
*
*/
public abstract class BasicTransactionSemantics implements Transaction {
private State state;
private long initialThreadId;
protected void doBegin() throws InterruptedException {}
protected abstract void doPut(Event event) throws InterruptedException;
protected abstract Event doTake() throws InterruptedException;
protected abstract void doCommit() throws InterruptedException;
protected abstract void doRollback() throws InterruptedException;
protected void doClose() {}
protected BasicTransactionSemantics() {
state = State.NEW;
initialThreadId = Thread.currentThread().getId();
}
/**
*
* The method to which {@link BasicChannelSemantics} delegates calls
* to put
.
*
*/
protected void put(Event event) {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"put() called from different thread than getTransaction()!");
Preconditions.checkState(state.equals(State.OPEN),
"put() called when transaction is %s!", state);
Preconditions.checkArgument(event != null,
"put() called with null event!");
try {
doPut(event);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ChannelException(e.toString(), e);
}
}
/**
*
* The method to which {@link BasicChannelSemantics} delegates calls
* to take
.
*
*/
protected Event take() {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"take() called from different thread than getTransaction()!");
Preconditions.checkState(state.equals(State.OPEN),
"take() called when transaction is %s!", state);
try {
return doTake();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
* @return the current state of the transaction
*/
protected State getState() {
return state;
}
@Override
public void begin() {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"begin() called from different thread than getTransaction()!");
Preconditions.checkState(state.equals(State.NEW),
"begin() called when transaction is " + state + "!");
try {
doBegin();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ChannelException(e.toString(), e);
}
state = State.OPEN;
}
@Override
public void commit() {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"commit() called from different thread than getTransaction()!");
Preconditions.checkState(state.equals(State.OPEN),
"commit() called when transaction is %s!", state);
try {
doCommit();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ChannelException(e.toString(), e);
}
state = State.COMPLETED;
}
@Override
public void rollback() {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"rollback() called from different thread than getTransaction()!");
Preconditions.checkState(state.equals(State.OPEN),
"rollback() called when transaction is %s!", state);
state = State.COMPLETED;
try {
doRollback();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ChannelException(e.toString(), e);
}
}
@Override
public void close() {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"close() called from different thread than getTransaction()!");
Preconditions.checkState(
state.equals(State.NEW) || state.equals(State.COMPLETED),
"close() called when transaction is %s"
+ " - you must either commit or rollback first", state);
state = State.CLOSED;
doClose();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("BasicTransactionSemantics: {");
builder.append(" state:").append(state);
builder.append(" initialThreadId:").append(initialThreadId);
builder.append(" }");
return builder.toString();
}
/**
*
* The state of the {@link Transaction} to which it belongs.
*
*
* - NEW
* - A newly created transaction that has not yet begun.
* - OPEN
* - A transaction that is open. It is permissible to commit or rollback.
*
* - COMPLETED
* - This transaction has been committed or rolled back. It is illegal to
* perform any further operations beyond closing it.
* - CLOSED
* - A closed transaction. No further operations are permitted.
*/
protected static enum State {
NEW, OPEN, COMPLETED, CLOSED
}
}