/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.bigdata.ha;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.rmi.Remote;
import java.security.DigestException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.bigdata.ha.msg.IHAAwaitServiceJoinRequest;
import com.bigdata.ha.msg.IHADigestRequest;
import com.bigdata.ha.msg.IHADigestResponse;
import com.bigdata.ha.msg.IHALogDigestRequest;
import com.bigdata.ha.msg.IHALogDigestResponse;
import com.bigdata.ha.msg.IHANotifyReleaseTimeResponse;
import com.bigdata.ha.msg.IHARemoteRebuildRequest;
import com.bigdata.ha.msg.IHARootBlockRequest;
import com.bigdata.ha.msg.IHARootBlockResponse;
import com.bigdata.ha.msg.IHASnapshotDigestRequest;
import com.bigdata.ha.msg.IHASnapshotDigestResponse;
import com.bigdata.ha.msg.IHASnapshotRequest;
import com.bigdata.ha.msg.IHASnapshotResponse;
import com.bigdata.journal.AbstractJournal;
import com.bigdata.quorum.AsynchronousQuorumCloseException;
import com.bigdata.quorum.QuorumException;
import com.bigdata.rdf.task.IApiTask;
import com.bigdata.service.IService;
/**
* A {@link Remote} interface for methods supporting high availability for a set
* of journals or data services having shared persistent state.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*
* @todo Scale-out needs to add {@link AbstractJournal#closeForWrites(long)} to
* this API and reconcile it with the methods to send index segments (and
* historical journal files) across the wire. Perhaps we need both an
* HAJournalGlue and an HADataServiceGlue interface?
*
* @todo The naming convention for these interfaces should be changed to follow
* the standard jini smart proxy naming pattern.
*/
public interface HAGlue extends HAGlueBase, HAPipelineGlue, HAReadGlue,
HACommitGlue, HATXSGlue, IService {
/*
* Administrative
*
* @todo Move to an HAAdminGlue interface?
*/
/**
* Await the service being ready to partitipate in an HA quorum. The
* preconditions include:
* <ol>
* <li>receiving notice of the quorum token via
* {@link #setQuorumToken(long)}</li>
* <li>The service is joined with the met quorum for that token</li>
* <li>If the service is a follower and it's local root blocks were at
* <code>commitCounter:=0</code>, then the root blocks from the leader have
* been installed on the follower.</li>
* <ol>
*
* @param timeout
* The timeout to await this condition.
* @param units
* The units for that timeout.
*
* @return the quorum token for which the service became HA ready.
*/
public long awaitHAReady(long timeout, TimeUnit unit) throws IOException,
InterruptedException, TimeoutException, QuorumException,
AsynchronousQuorumCloseException;
/**
* A follower uses this message to request that the quorum leader await the
* visibility of the zookeeper event in which the service join becomes
* visible to the leader. This is invoked while holding a lock that blocks
* pipeline replication, so the leader can not flush the write replication
* pipeline and enter the commit. The callback to the leader ensures that
* the service join is visible to the leader before the leader makes an
* atomic decision about the set of services that are joined with the met
* quorum for a 2-phase commit.
*
* @param req
* The request.
*
* @return The most recent consensus release time for the quorum leader.
* This information is used to ensure that a service which joins
* after a gather and before a PREPARE will join with the correct
* release time for its local journal and thus will not permit
* transactions to start against commit points which have been
* recycled by the quorum leader.
*
* @throws InterruptedException
* @throws TimeoutException
* if the timeout is exceeded before the service join becomes
* visible to this service.
*
* @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/681" >
* HAJournalServer deadlock: pipelineRemove() and getLeaderId()</a>
*/
public IHANotifyReleaseTimeResponse awaitServiceJoin(
IHAAwaitServiceJoinRequest req) throws IOException,
InterruptedException, TimeoutException;
/*
* Synchronization.
*
* Various methods to support synchronization between services as they join
* a quorum.
*
* @todo Move to an HASyncGlue interface?
*/
/**
* Return the then current root block for the persistence store.
* <p>
* Note: The initial root blocks are identical, so this may be used to
* create a new journal in a quorum by replicating the root blocks of the
* quorum leader.
*
* @param msg
* The message requesting the then current root block.
*
* @return The then current root block.
*/
IHARootBlockResponse getRootBlock(IHARootBlockRequest msg)
throws IOException;
/**
* The port that the NanoSparqlServer is running on.
*/
int getNSSPort() throws IOException;
/**
* The {@link RunState} of the service - this does NOT tell you whether the
* service is ready to act as a leader or follower.
*/
RunState getRunState() throws IOException;
/**
* The extended run state of the service - this embeds more information but
* is not designed for progamatic interpretation.
*/
String getExtendedRunState() throws IOException;
/**
* A simplified summary of the HA status of the service. This may be used to
* reliably decide whether the service is the {@link HAStatusEnum#Leader}, a
* {@link HAStatusEnum#Follower}, or {@link HAStatusEnum#NotReady}. This is
* exposed both here (an RMI interface) and by the REST API.
*/
HAStatusEnum getHAStatus() throws IOException;
/**
* Compute the digest of the entire backing store - <strong>THIS METHOD IS
* ONLY FOR DIAGNOSTIC PURPOSES.</strong>
* <p>
* The digest is useless if there are concurrent writes since it can not be
* meaningfully compared with the digest of another store unless both stores
* are known to be stable.
*/
IHADigestResponse computeDigest(IHADigestRequest req) throws IOException,
NoSuchAlgorithmException, DigestException;
/**
* Compute the digest of the entire HALog file - <strong>THIS METHOD IS ONLY
* FOR DIAGNOSTIC PURPOSES.</strong>
* <p>
* The digest is useless if there are concurrent writes since it can not be
* meaningfully compared with the digest of another store unless both stores
* are known to be stable.
*
* @throws FileNotFoundException
* if the HALog for the specified commit point does not exist.
*/
IHALogDigestResponse computeHALogDigest(IHALogDigestRequest req) throws IOException,
NoSuchAlgorithmException, DigestException;
/**
* Compute the digest of the entire snapshot file - <strong>THIS METHOD IS
* ONLY FOR DIAGNOSTIC PURPOSES.</strong> This digest is computed for the
* compressed data so it may be compared directly with the digest of the
* backing store from which the snapshot was obtained.
*
* @throws FileNotFoundException
* if no snapshot exists for that commit point.
*/
IHASnapshotDigestResponse computeHASnapshotDigest(IHASnapshotDigestRequest req)
throws IOException, NoSuchAlgorithmException, DigestException;
// /**
// * Obtain a global write lock on the leader. The lock only blocks writers.
// * Readers may continue to execute without delay.
// * <p>
// * You can not obtain a coherent backup of the {@link Journal} while there
// * are concurrent write operations. This method may be used to coordinate
// * full backups of the {@link Journal} by suspending low level writes on the
// * backing file.
// * <p>
// * This method will block until the lock is held, the lock request is
// * interrupted, or the lock request timeout expires.
// *
// * @param req
// * The request.
// *
// * @return A {@link Future} for the lock. The lock may be released by
// * canceling the {@link Future}. The lock is acquired before this
// * method returns and is held while the {@link Future} is running.
// * If the {@link Future#isDone()} then the lock is no longer held.
// *
// * @throws IOException
// * if there is an RMI problem.
// * @throws TimeoutException
// * if a timeout expires while awaiting the global lock.
// * @throws InterruptedException
// * if interrupted while awaiting the lock.
// *
// * @deprecated This is no longer necessary to support backups since we can
// * now take snapshots without suspending writers.
// * @see https://sourceforge.net/apps/trac/bigdata/ticket/566 (
// * Concurrent unisolated operations against multiple KBs on the
// * same Journal)
// */
// @Deprecated
// Future<Void> globalWriteLock(IHAGlobalWriteLockRequest req)
// throws IOException, TimeoutException, InterruptedException;
/**
* Request that the service take a snapshot. If there is already a snapshot
* in progress, then the {@link Future} for that request will be returned.
*
* @param req
* The request (optional). When <code>null</code>, the
* {@link Future} for any existing snapshot operation will be
* returned but the request WILL NOT schedule a snapshot if none
* is running.
*
* @return A {@link Future} for the snapshot -or- <code>null</code> if no
* snapshot is running and none will be taken for that request.
*/
Future<IHASnapshotResponse> takeSnapshot(IHASnapshotRequest req)
throws IOException;
/**
* Disaster recovery (REBUILD) of the local database instance from the
* leader of a met quorum.
*
* There are several preconditions:
* <ul>
*
* <li>The quorum must be met and there must be an
* {@link HAStatusEnum#Ready} leader.</li>
*
* <li>This service must be {@link HAStatusEnum#NotReady}.</li>
*
* <li>This service MUST NOT be at the same commit point as the leader (if
* it is, then the service could meet in a data race with the met quorum and
* we do not permit RESTORE if the service is joined with the met quorum).</li>
*
* <li>The {@link HAJournalServer} must not be running a RESTORE (we don't
* want it to accidentally interrupt a RESTORE that is in progress).</li>
*
* </ul>
*
* @return The (asynchronous) {@link Future} of the REBUILD operation -or-
* <code>null</code> if any of the pre-conditions were violated.
*/
Future<Void> rebuildFromLeader(IHARemoteRebuildRequest req)
throws IOException;
/**
* Run the caller's task on the service.
* <p>
* Note: This interface provides direct access to the raw index manager.
* Caller's requiring concurrency control should submit an {@link IApiTask}
* in order to have their task queue for the necessary locks and run on the
* appropriate executor service.
*
* @param callable
* The task to run on the service.
* @param asyncFuture
* <code>true</code> if the task will execute asynchronously
* and return a {@link Future} for the computation that may
* be used to inspect and/or cancel the computation.
* <code>false</code> if the task will execute synchronously
* and return a thick {@link Future}.
*/
public <T> Future<T> submit(IIndexManagerCallable<T> callable,
boolean asyncFuture) throws IOException;
}