ReplicationImpl.java :  » Database-DBMS » db4o-6.4 » com » db4o » Java Open Source

Java Open Source » Database DBMS » db4o 6.4 
db4o 6.4 » com » db4o » ReplicationImpl.java
/* Copyright (C) 2004 - 2007  db4objects Inc.  http://www.db4o.com

This file is part of the db4o open source object database.

db4o is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL 
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.

db4o 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.db4o;

import com.db4o.ext.*;
import com.db4o.internal.*;
import com.db4o.internal.replication.*;
import com.db4o.query.*;
import com.db4o.replication.*;

/**
 * @exclude
 * @deprecated
 */
public class ReplicationImpl implements ReplicationProcess {

    final ObjectContainerBase _peerA;

    final Transaction _transA;

    final ObjectContainerBase _peerB;

    final Transaction _transB;

    final ReplicationConflictHandler _conflictHandler;

    final ReplicationRecord _record;

    private int _direction;

    private static final int IGNORE = 0;

    private static final int TO_B = -1;

    private static final int TO_A = 1;

    private static final int CHECK_CONFLICT = -99;
    
  public ReplicationImpl(ObjectContainerBase peerA, ObjectContainerBase peerB,
      ReplicationConflictHandler conflictHandler) {
        
        if(conflictHandler == null){
            // We don't allow starting replication without a 
            // conflict handler, so we don't get late failures.
            throw new NullPointerException();
        }
        
        synchronized (peerA.lock()) {
      synchronized (peerB.lock()) {

        _peerA = peerA;
        _transA = peerA.checkTransaction();

        _peerB = peerB;
        _transB = _peerB.checkTransaction(null);

        MigrationConnection mgc = new MigrationConnection(_peerA, _peerB);

        _peerA._handlers.migrationConnection(mgc);
        _peerA._handlers.replication(this);
        _peerA.replicationCallState(Const4.OLD);

        _peerB._handlers.migrationConnection(mgc);
        _peerB._handlers.replication(this);
                _peerB.replicationCallState(Const4.OLD);

        _conflictHandler = conflictHandler;

        _record = ReplicationRecord.beginReplication(_transA, _transB);
      }
    }
        
  }

    private int bindAndSet(Transaction trans, ObjectContainerBase peer, ObjectReference ref, Object sourceObject){
        if(sourceObject instanceof Db4oTypeImpl){
            Db4oTypeImpl db4oType = (Db4oTypeImpl)sourceObject;
            if(! db4oType.canBind()){
                Db4oTypeImpl targetObject = (Db4oTypeImpl)ref.getObject();
                targetObject.replicateFrom(sourceObject);
                return ref.getID();
            }
        }
        peer.bind2(trans, ref, sourceObject);
        return peer.setAfterReplication(trans, sourceObject, 1, true);
    }

  public void checkConflict(Object obj) {
    int temp = _direction;
    _direction = CHECK_CONFLICT;
    replicate(obj);
    _direction = temp;
  }

  public void commit() {
        synchronized (_peerA.lock()) {
            synchronized (_peerB.lock()) {
        
            _peerA.commit(_transA);
            _peerB.commit(_transB);
        
                endReplication();
        
            long versionA = _peerA.currentVersion();
            long versionB = _peerB.currentVersion();
        
            _record._version = (versionA > versionB) ? versionA :versionB;
                
                _peerA.raiseVersion(_record._version + 1);
                _peerB.raiseVersion(_record._version + 1);
        
            _record.store(_peerA);
            _record.store(_peerB);
            }
        }
  }

  private void endReplication() {
        
    _peerA.replicationCallState(Const4.NONE);
        _peerA._handlers.migrationConnection(null);
    _peerA._handlers.replication(null);
        
        _peerA.replicationCallState(Const4.NONE);
        _peerB._handlers.migrationConnection(null);
    _peerB._handlers.replication(null);
  }
    
    private int idInCaller(ObjectContainerBase caller, ObjectReference referenceA, ObjectReference referenceB){
        return (caller == _peerA) ? referenceA.getID() : referenceB.getID();
    }

  private int ignoreOrCheckConflict() {
    if (_direction == CHECK_CONFLICT) {
      return CHECK_CONFLICT;
    }
    return IGNORE;
  }
  
  private boolean isInConflict(long versionA, long versionB) {
    if(versionA > _record._version && versionB > _record._version) {
      return true;
    }
    if(versionB > _record._version && _direction == TO_B) {
      return true;
    }
    if(versionA > _record._version && _direction == TO_A) {
      return true;
    }
    return false;
  }

  private long lastSynchronization() {
    return _record._version;
  }
    
  public ObjectContainer peerA() {
    return (ObjectContainer)_peerA;
  }

  public ObjectContainer peerB() {
    return (ObjectContainer)_peerB;
  }
    
  public void replicate(Object obj) {

    // When there is an active replication process, the set() method
    // will call back to the #process() method in this class.

    // This detour is necessary, since #set() has to handle all cases
    // anyway, for members of the replicated object, especially the
    // prevention of endless loops in case of circular references.

    ObjectContainerBase container = _peerB;
    Transaction trans = _transB;

    if (_peerB.isStored(_transB, obj)) {
      if (!_peerA.isStored(_transA, obj)) {
        container = _peerA;
        trans = _transA;
      }
    }

    container.set(trans, obj);
  }

  public void rollback() {
    _peerA.rollback(_transA);
    _peerB.rollback(_transB);
    endReplication();
  }

  public void setDirection(ObjectContainer replicateFrom,
      ObjectContainer replicateTo) {
    if (replicateFrom == _peerA && replicateTo == _peerB) {
      _direction = TO_B;
    }
    if (replicateFrom == _peerB && replicateTo == _peerA) {
      _direction = TO_A;
    }
  }

  private void shareBinding(ObjectReference sourceReference, ObjectReference referenceA, Object objectA, ObjectReference referenceB, Object objectB) {
    if(sourceReference == null) {
      return;
    }
        if(objectA instanceof Db4oTypeImpl){
            if(! ((Db4oTypeImpl)objectA).canBind() ){
                return;
            }
        }
        
    if(sourceReference == referenceA) {
      _peerB.bind2(_transB, referenceB, objectA);
    }else {
      _peerA.bind2(_transA, referenceA, objectB);
    }
  }

  private int toA() {
    if (_direction == CHECK_CONFLICT) {
      return CHECK_CONFLICT;
    }
    if (_direction != TO_B) {
      return TO_A;
    }
    return IGNORE;
  }

  private int toB() {
    if (_direction == CHECK_CONFLICT) {
      return CHECK_CONFLICT;
    }
    if (_direction != TO_A) {
      return TO_B;
    }
    return IGNORE;
  }
    
  
  /**
   * called by YapStream.set()
   * @return id of reference in caller or 0 if not handled or -1
     * if #set() should stop processing because of a direction 
     * setting.
   */
  public int tryToHandle(ObjectContainerBase caller, Object obj) {
        
        int notProcessed = 0;
        ObjectContainerBase other = null;
        ObjectReference sourceReference = null;
        
        if(caller == _peerA){
            other = _peerB;
            if(_direction == TO_B){
                notProcessed = -1;
            }
        }else{
            other = _peerA;
            if(_direction == TO_A){
                notProcessed = -1;
            }
        }
        
    synchronized (other._lock) {
            
      Object objectA = obj;
      Object objectB = obj;
      
      ObjectReference referenceA = _transA.referenceForObject(obj);
      ObjectReference referenceB = _transB.referenceForObject(obj);
      
      VirtualAttributes attA = null;
      VirtualAttributes attB = null;
      
      if (referenceA == null) {
        if(referenceB == null) {
          return notProcessed;
        }
        
        sourceReference = referenceB;
        
        attB = referenceB.virtualAttributes(_transB);
                if(attB == null){
                    return notProcessed;
                }
        
        HardObjectReference hardRef = _transA.getHardReferenceBySignature(attB.i_uuid,
            attB.i_database.i_signature);
        if (hardRef._object == null) {
          return notProcessed;
        }
        
        referenceA = hardRef._reference;
        objectA = hardRef._object;
        
        attA = referenceA.virtualAttributes(_transA);
      }else {
        
        attA = referenceA.virtualAttributes(_transA);
                if(attA == null){
                    return notProcessed;
                }
        
        if(referenceB == null) {
                    
          sourceReference = referenceA;
                    
          HardObjectReference hardRef = _transB.getHardReferenceBySignature(attA.i_uuid,
              attA.i_database.i_signature);
                    
          if (hardRef._object == null) {
            return notProcessed;
          }
                    
          referenceB =  hardRef._reference;
          objectB = hardRef._object;
                    
        }
        
        attB = referenceB.virtualAttributes(_transB);
      }
            
            if(attA == null || attB == null){
                return notProcessed;
            }
      
      if(objectA == objectB) {
        if(caller == _peerA && _direction == TO_B) {
          return -1;
        }
        if(caller == _peerB && _direction == TO_A) {
          return -1;
        }
        return idInCaller(caller, referenceA, referenceB);
      }
      
      _peerA.refresh(_transA, objectA, 1);
      _peerB.refresh(_transB, objectB, 1);
      
      if (attA.i_version <= _record._version
          && attB.i_version <= _record._version) {

        if (_direction != CHECK_CONFLICT) {
          shareBinding(sourceReference, referenceA, objectA, referenceB, objectB);
        }
                return idInCaller(caller, referenceA, referenceB);
      }

      int direction = ignoreOrCheckConflict();

      if (isInConflict(attA.i_version, attB.i_version)) {
                
        Object prevailing = _conflictHandler.resolveConflict(this,
            objectA, objectB);

        if (prevailing == objectA) {
          direction = (_direction == TO_A) ? IGNORE : toB(); 
        }

        if (prevailing == objectB) {
          direction = (_direction == TO_B) ? IGNORE : toA();
        }

        if (direction == IGNORE) {
          return -1;
        }

      } else {
        direction = attB.i_version > _record._version ? toA(): toB();
      }

      if (direction == TO_A) {
        if (!referenceB.isActive()) {
          referenceB.activate(_transB, objectB, 1, false);
        }
                int idA = bindAndSet(_transA, _peerA, referenceA, objectB);
                if(caller == _peerA){
                    return idA;
                }
      }

      if (direction == TO_B) {
        if (!referenceA.isActive()) {
          referenceA.activate(_transA, objectA, 1, false);
        }
                int idB = bindAndSet(_transB, _peerB, referenceB, objectA);
                if(caller == _peerB){
                    return idB;
                }
      }

            return idInCaller(caller, referenceA, referenceB);
    }

  }
    
  public void whereModified(Query query) {
    query.descend(VirtualField.VERSION).constrain(
        new Long(lastSynchronization())).greater();
  }
 
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.