All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.ha.QuorumServiceBase Maven / Gradle / Ivy

/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     [email protected]

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
*/
/*
 * Created on Jun 1, 2010
 */

package com.bigdata.ha;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;

import org.apache.log4j.Logger;

import com.bigdata.ha.msg.IHASendState;
import com.bigdata.ha.msg.IHASyncRequest;
import com.bigdata.ha.msg.IHAWriteMessage;
import com.bigdata.journal.AbstractJournal;
import com.bigdata.journal.IResourceManager;
import com.bigdata.journal.IRootBlockView;
import com.bigdata.journal.Journal;
import com.bigdata.quorum.AbstractQuorumMember;
import com.bigdata.service.proxy.ThickFuture;
import com.bigdata.util.InnerCause;

/**
 * Abstract implementation provides the logic for distributing messages for the
 * quorum 2-phase commit protocol, failover reads, etc.
 * 
 * @author Bryan Thompson
 * @version $Id$
 * 
 * @todo Change the generic type of  to {@link IResourceManager}.
 */
abstract public class QuorumServiceBase
        extends AbstractQuorumMember implements QuorumService {

    static protected transient final Logger log = Logger
            .getLogger(QuorumServiceBase.class);

    private final S service;

    private final L localService;

    private final QuorumPipelineImpl pipelineImpl;

    private final QuorumCommitImpl commitImpl;

    private final QuorumReadImpl readImpl;

    /**
     * @param logicalServiceId
     *            The identifier of the logical service.
     * @param serviceId
     *            The {@link UUID} for this service (a physical instance of the
     *            logical service).
     * @param service
     *            The interface for the local service that is exposed to remote
     *            clients (typically as a smart proxy).
     * @param localService
     *            The local service implementation.
     */ 
    protected QuorumServiceBase(final String logicalServiceId,
            final UUID serviceId, final S service, final L localService) {

        super(logicalServiceId, serviceId);

        if (localService == null)
            throw new IllegalArgumentException();

        this.service = service;
        
        this.localService = localService;

        /*
         * Delegates. 
         */
        
        addListener(this.pipelineImpl = new QuorumPipelineImpl(this) {

            @Override
            protected void handleReplicatedWrite(final IHASyncRequest req,
                    final IHAWriteMessage msg, final ByteBuffer data)
                    throws Exception {

                QuorumServiceBase.this.handleReplicatedWrite(req, msg, data);

            }
            
            @Override
            protected void incReceive(final IHASyncRequest req,
                    final IHAWriteMessage msg, final int nreads,
                    final int rdlen, final int rem) throws Exception {

                QuorumServiceBase.this.incReceive(req, msg, nreads, rdlen, rem);

            }
            
            @Override
            protected long getRetrySendTimeoutNanos() {

                return QuorumServiceBase.this.getRetrySendTimeoutNanos();
                
            }
            
            @Override
            public UUID getStoreUUID() {

                return QuorumServiceBase.this.getStoreUUID();
                
            }
        
            @Override
            public long getLastCommitTime() {

                return QuorumServiceBase.this.getLastCommitTime();
                
            }
        
            @Override
            public long getLastCommitCounter() {

                return QuorumServiceBase.this.getLastCommitCounter();
                
            }

            @Override
            public void logWriteCacheBlock(final IHAWriteMessage msg,
                    final ByteBuffer data) throws IOException {

                QuorumServiceBase.this.logWriteCacheBlock(msg, data);
                
            }
            
            @Override
            public void logRootBlock(//final boolean isJoinedService,
                    final IRootBlockView rootBlock) throws IOException {

                QuorumServiceBase.this.logRootBlock(/*isJoinedService,*/ rootBlock);

            }

            @Override
            public void purgeHALogs(final long token) {

                QuorumServiceBase.this.purgeHALogs(token);

            }

        });

        addListener(this.commitImpl = new QuorumCommitImpl(this));

        addListener(this.readImpl = new QuorumReadImpl(this));
        
    }
    
    abstract protected long getRetrySendTimeoutNanos();

    @Override
    public S getService() {
        
        return service;
        
    }

    /**
     * {@inheritDoc}
     */
    @Override
    abstract public S getService(UUID serviceId);

    /**
     * FIXME Return the {@link IResourceManager}, {@link Journal}, [@link
     * DataService}, etc. Probably rename to getResourceManager().
     */
    protected L getLocalService() {
        
        return localService;
        
    }
    
    @Override
    public ExecutorService getExecutor() {

        return getLocalService().getExecutorService();
        
    }

    // @todo fast code path for self? or use RMI proxy for self?
//  public S getService(UUID serviceId) {
//      return null;
//  }

    /*
     * QuorumPipeline
     */
    
//    @Override
//    public HAReceiveService getHAReceiveService() {
//        
//        return pipelineImpl.getHAReceiveService();
//        
//    }

//    @Override
//    public HASendService getHASendService() {
//        
//        return pipelineImpl.getHASendService();
//        
//    }

    @Override
    public Future receiveAndReplicate(final IHASyncRequest req,
            final IHASendState snd, final IHAWriteMessage msg)
            throws IOException {

        return pipelineImpl.receiveAndReplicate(req, snd, msg);
        
    }

    @Override
    public Future replicate(final IHASyncRequest req,
            final IHAWriteMessage msg, final ByteBuffer b) throws IOException {

        return pipelineImpl.replicate(req, msg, b);

    }

    @Override
    public Future resetPipeline(
            IHAPipelineResetRequest req) throws IOException {

        return pipelineImpl.resetPipeline(req);

    }

    /**
     * Core implementation handles the message and payload when received on a
     * service.
     * 

* Note: Replication of the message and payload is handled by the caller. * The implementation of this method is NOT responsible for replication. * * @param req * The synchronization request (optional). When non- * null the message and payload are historical data. * When null they are live data. * @param msg * Metadata about a buffer containing data replicated to this * node. * @param data * The buffer containing the data. * * @throws Exception * * @see QuorumPipelineImpl#handleReplicatedWrite(IHAWriteMessage, * ByteBuffer) */ abstract protected void handleReplicatedWrite(IHASyncRequest req, IHAWriteMessage msg, ByteBuffer data) throws Exception; /** * Core implementation of callback for monitoring progress of replicated * writes. * * @param req * The synchronization request (optional). When non- * null the message and payload are historical data. * When null they are live data. * @param msg * Metadata about a buffer containing data replicated to this * node. * @param rdlen * The number of bytes read from the socket in this read. * @param rem * The number of bytes remaining before the payload has been * fully read. * * @throws Exception */ abstract protected void incReceive(final IHASyncRequest req, final IHAWriteMessage msg, final int nreads, final int rdlen, final int rem) throws Exception; /** * {@inheritDoc} *

* Note: The default implementation is a NOP. */ @Override public void logWriteCacheBlock(final IHAWriteMessage msg, final ByteBuffer data) throws IOException { // NOP } /** * {@inheritDoc} *

* Note: The default implementation is a NOP. */ @Override public void purgeHALogs(final long token) { // NOP } /** * {@inheritDoc} *

* Note: The default implementation is a NOP. */ @Override public void logRootBlock(//final boolean isJoinedService, final IRootBlockView rootBlock) throws IOException { // NOP } /* * QuorumCommit. */ @Override public void abort2Phase(final long token) throws IOException, InterruptedException { commitImpl.abort2Phase(token); } @Override public CommitResponse commit2Phase(final CommitRequest req) throws IOException, InterruptedException { return commitImpl.commit2Phase(req); } @Override public PrepareResponse prepare2Phase(final PrepareRequest req) throws InterruptedException, TimeoutException, IOException { return commitImpl.prepare2Phase(req); } @Override final public UUID getStoreUUID() { final L localService = getLocalService(); return localService.getRootBlockView().getUUID(); } @Override final public long getLastCommitTime() { final L localService = getLocalService(); return localService.getRootBlockView().getLastCommitTime(); } @Override final public long getLastCommitCounter() { final L localService = getLocalService(); return localService.getRootBlockView().getCommitCounter(); } // @Override // final public File getHALogDir() { // // return getLocalService().getHALogDir(); // // } @Override public long getPrepareTimeout() { return getLocalService().getHAPrepareTimeout(); } /* * QuorumRead */ @Override public byte[] readFromQuorum(UUID storeId, long addr) throws InterruptedException, IOException { return readImpl.readFromQuorum(storeId, addr); } /** * Called from ErrorTask in HAJournalServer to ensure that events are * processed before entering SeekConsensus. * * @see * HAJournalServer reports "follower" but is in SeekConsensus and is not * participating in commits */ protected void processEvents() { pipelineImpl.processEvents(); } /** * Cancel the requests on the remote services (RMI). This is a best effort * implementation. Any RMI related errors are trapped and ignored in order * to be robust to failures in RMI when we try to cancel the futures. *

* NOte: This is not being done in parallel. However, due to a DGC thread * leak issue, we now use {@link ThickFuture}s. Thus, the tasks that are * being cancelled are all local tasks running on the * {@link #executorService}. If that local task is doing an RMI, then * cancelling it will cause an interrupt in the NIO request. */ public static , T> void cancelFutures( final List futures) { if (log.isInfoEnabled()) log.info(""); for (F f : futures) { if (f == null) { continue; } try { if (!f.isDone()) { f.cancel(true/* mayInterruptIfRunning */); } } catch (Throwable t) { if (InnerCause.isInnerCause(t, InterruptedException.class)) { // Propagate interrupt. Thread.currentThread().interrupt(); } // ignored (to be robust). } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy