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

com.gemstone.org.jgroups.blocks.ReplicationManager Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/** Notice of modification as required by the LGPL
 *  This file was modified by Gemstone Systems Inc. on
 *  $Date$
 **/
// $Id: ReplicationManager.java,v 1.7 2004/09/23 16:29:11 belaban Exp $

package com.gemstone.org.jgroups.blocks;

import com.gemstone.org.jgroups.util.GemFireTracer;
import com.gemstone.org.jgroups.util.ExternalStrings;
import com.gemstone.org.jgroups.*;
import com.gemstone.org.jgroups.util.RspList;

import java.io.Serializable;





/**
 * Class to propagate updates to a number of nodes in various ways:
 * 
    *
  1. Asynchronous *
  2. Synchronous *
  3. Synchronous with locking *
* *
Note: This class is experimental as of Oct 2002 * * @author Bela Ban Oct 2002 */ public class ReplicationManager implements RequestHandler { Address local_addr=null; ReplicationReceiver receiver=null; /** Used to broadcast updates and receive responses (latter only in synchronous case) */ protected MessageDispatcher disp=null; protected final GemFireTracer log=GemFireTracer.getLog(this.getClass()); /** * Creates an instance of ReplicationManager on top of a Channel */ public ReplicationManager(Channel channel, MessageListener ml, MembershipListener l, ReplicationReceiver receiver) { setReplicationReceiver(receiver); if(channel != null) { local_addr=channel.getLocalAddress(); disp=new MessageDispatcher(channel, ml, l, this, // ReplicationManager is RequestHandler true); // use deadlock detection } } /** * Creates an instance of ReplicationManager on top of a PullPushAdapter */ public ReplicationManager(PullPushAdapter adapter, Serializable id, MessageListener ml, MembershipListener l, ReplicationReceiver receiver) { if(adapter != null && adapter.getTransport() != null && adapter.getTransport() instanceof Channel) local_addr=((Channel)adapter.getTransport()).getLocalAddress(); setReplicationReceiver(receiver); disp=new MessageDispatcher(adapter, id, // FIXME ml, l, this); // ReplicationManager is RequestHandler disp.setDeadlockDetection(true); } public void stop() { if(disp != null) disp.stop(); } /** * Create a new transaction. The transaction will be used to send updates, identify updates in the same transaction, * and eventually commit or rollback the changes associated with the transaction. * @return Xid A unique transaction * @exception Exception Thrown when local_addr is null */ public Xid begin() throws Exception { return begin(Xid.DIRTY_READS); } /** * Create a new transaction. The tracsion will be used to send updates, identify updates in the same transaction, * and eventually commit or rollback the changes associated with the transaction. * @param transaction_mode Mode in which the transaction should run. Possible values are Xid.DIRTY_READS, * Xid.READ_COMMITTED, Xid.REPEATABLE_READ and Xid.SERIALIZABLE * @return Xid A unique transaction * @exception Exception Thrown when local_addr is null */ public Xid begin(int transaction_mode) throws Exception { return Xid.create(local_addr, transaction_mode); } public void setReplicationReceiver(ReplicationReceiver handler) { this.receiver=handler; } public void setMembershipListener(MembershipListener l) { if(l == null) return; if(disp == null) { // GemStoneAddition: missing braces if(log.isErrorEnabled()) log.error(ExternalStrings.ReplicationManager_DISPATCHER_IS_NULL_CANNOT_SET_MEMBERSHIPLISTENER); } else disp.setMembershipListener(l); } /** * Sends a request to all members of the group. Sending is asynchronous (return immediately) or * synchronous (wait for all members to respond). If use_locking is true, then locking * will be used at the receivers to acquire locks before accessing/updating a resource. Locks can be * explicitly set using lock_info or implicitly through data. In the latter * case, locks are induced from the data sent, e.g. if the data is a request for updating a certain row * in a table, then we need to acquire a lock for that table.

* In case of using locks, if the transaction associated with update already has a lock for a given resource, * we will return. Otherwise, we will wait for lock_acquisition_timeout milliseconds. If the lock * is not granted within that time a LockingException will be thrown. (We hope to * replace this timeout with a distributed deadlock detection algorithm in the future.)

* We have 3 main use case for this method: *

    *
  1. Asynchronous: sends the message and returns immediately. Argument asynchronous * needs to be true. All other arguments except data are ignored and can be null. Will call * update() on the registered ReplicationReceiver at each receiver. *
  2. Synchronous without locks: sends the message, but returns only after responses from all members * have been received, or synchronous_timeout milliseconds have elapsed (whichever comes * first). Argument asynchronous needs to be false. Argument synchronous_timeout * needs to be >= 0. If it is null the call will not time out, but wait for all responses. * All other arguments (besides data are ignored). *
  3. Synchronous with locks: sends the message, but returns only after responses from all members * have been received, or synchronous_timeout milliseconds have elapsed (whichever comes * first). At the receiver's side we have to acquire a lock for the resource to be updated, if the * acquisition fails a LockingException will be thrown. The resource to be locked can be found in two ways: * either data contains the resource(c) to be acquired implicitly, or lock_info * lists the resources explicitly, or both. All the locks acquired at the receiver's side should be associated * with transaction. When a commit() is received, the receiver should commit * the modifications to the resource and release all locks. When a rollback() is received, * the receiver should remove all (temporary) modifications and release all locks associated with * transaction. *
* In both the synchronous cases a List of byte[] will be returned if the data was sent to all receivers * successfully, cointaining byte buffers. The list may be empty. * @param dest The destination to which to send the message. Will be sent to all members if null. * @param data The data to be sent to all members. It may contain information about the resource to be locked. * @param synchronous If false the call is asynchronous, ie. non-blocking. If true, the method will wait * until responses from all members have been received (unless a timeout is defined, see below) * @param synchronous_timeout In a synchronous call, we will wait for responses from all members or until * synchronous_timeout have elapsed (whichever comes first). 0 means * to wait forever. * @param transaction The transaction under which all locks for resources should be acquired. The receiver * will probably maintain a lock table with resources as keys and transactions as values. * When an update is received, the receiver checks its lock table: if the resource is * not yet taken, the resource/transaction pair will be added to the lock table. Otherwise, * we check if the transaction's owner associated with the resource is the same as the caller. * If this is the case, the lock will be considered granted, otherwise we will wait for the * resource to become available (for a certain amount of time). When a transaction is * committed or rolled back, all resources associated with this transaction will be released. * @param lock_info Information about resource(s) to be acquired. This may be null, e.g. if this information * is already implied in data. Both data and lock_info * may be used to define the set of resources to be acquired. * @param lock_acquisition_timeout The number of milliseconds to wait until a lock acquisition request is * considered failed (causing a LockingException). If 0 we will wait forever. * (Note that this may lead to deadlocks). * @param lock_lease_timeout The number of milliseconds we want to keep the lock for a resource. After * this time has elapsed, the lock will be released. If 0 we won't release the lock(s) * @param use_locks If this is false, we will ignore all lock information (even if it is specified) and * not use locks at all. * @return RspList A list of Rsps ({@link com.gemstone.org.jgroups.util.Rsp}), one for each member. Each one is the result of * {@link ReplicationReceiver#receive}. If a member didn't send a response, the received * field will be false. If the member was suspected while waiting for a response, the * suspected field will be true. If the receive() method in the receiver returned * a value it will be in field retval. If the receiver threw an exception it will also * be in this field. */ public RspList send(Address dest, byte[] data, boolean synchronous, long synchronous_timeout, Xid transaction, byte[] lock_info, long lock_acquisition_timeout, long lock_lease_timeout, boolean use_locks) { // throws UpdateException, TimeoutException, LockingException { Message msg=null; ReplicationData d=new ReplicationData(ReplicationData.SEND, data, transaction, lock_info, lock_acquisition_timeout, lock_lease_timeout, use_locks); if(log.isInfoEnabled()) log.info(ExternalStrings.ReplicationManager_DATA_IS__0__SYNCHRONOUS_1, new Object[] {d, Boolean.valueOf(synchronous)}); msg=new Message(dest, null, d); if(synchronous) { return disp.castMessage(null, msg, GroupRequest.GET_ALL, synchronous_timeout); } else { disp.castMessage(null, msg, GroupRequest.GET_NONE, 0); return null; } } /** * Commits all modifications sent to the receivers via {@link #send} and releases all locks associated with * this transaction. If modifications were made to stable storage (but not to resource), those modifications * would now need to be transferred to the resource (e.g. database). */ public void commit(Xid transaction) { sendMessage(ReplicationData.COMMIT, transaction); } /** * Discards all modifications sent to the receivers via {@link #send} and releases all locks associated with * this transaction. */ public void rollback(Xid transaction) { sendMessage(ReplicationData.ROLLBACK, transaction); } /* ------------------------------- RequestHandler interface ------------------------------ */ public Object handle(Message msg) { Object retval=null; ReplicationData data; if(msg == null) { if(log.isErrorEnabled()) log.error(ExternalStrings.ReplicationManager_RECEIVED_MESSAGE_WAS_NULL); return null; } if(msg.getLength() == 0) { if(log.isErrorEnabled()) log.error(ExternalStrings.ReplicationManager_PAYLOAD_OF_RECEIVED_MESSAGE_WAS_NULL); return null; } try { data=(ReplicationData)msg.getObject(); } catch(Throwable ex) { if(log.isErrorEnabled()) log.error(ExternalStrings.ReplicationManager_FAILURE_UNMARSHALLING_MESSAGE__0, ex); return null; } switch(data.getType()) { case ReplicationData.SEND: try { return handleSend(data); } catch(Throwable ex) { if(log.isErrorEnabled()) log.error(ExternalStrings.ReplicationManager_FAILED_HANDLING_UPDATE__0, ex); return ex; } case ReplicationData.COMMIT: handleCommit(data.getTransaction()); break; case ReplicationData.ROLLBACK: handleRollback(data.getTransaction()); break; default: if(log.isErrorEnabled()) log.error(ExternalStrings.ReplicationManager_RECEIVED_INCORRECT_REPLICATION_MESSAGE__0, data); return null; } return retval; } /* --------------------------- End of RequestHandler interface---------------------------- */ protected Object handleSend(ReplicationData data) throws UpdateException, LockingException { try { if(receiver == null) { if(log.isWarnEnabled()) log.warn("receiver is not set"); return null; } return receiver.receive(data.getTransaction(), data.getData(), data.getLockInfo(), data.getLockAcquisitionTimeout(), data.getLockLeaseTimeout(), data.useLocks()); } catch(Throwable ex) { return ex; } } protected void handleCommit(Xid transaction) { if(receiver == null) { if(log.isWarnEnabled()) log.warn("receiver is not set"); } else receiver.commit(transaction); } protected void handleRollback(Xid transaction) { if(receiver == null) { if(log.isWarnEnabled()) log.warn("receiver is not set"); } else receiver.rollback(transaction); } /* -------------------------------------- Private methods ------------------------------------ */ void sendMessage(int type, Xid transaction) { ReplicationData data=new ReplicationData(type, null, transaction, null, 0, 0, false); Message msg=new Message(null, null, data); disp.castMessage(null, msg, GroupRequest.GET_NONE, 0); // send commit message asynchronously } /* ---------------------------------- End of Private methods --------------------------------- */ }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy