<commit_before>/*
 
   Derby - Class
   org.apache.derby.impl.services.replication.master.MasterController
 
   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.derby.impl.services.replication.master;

import java.io.IOException;
import java.net.SocketTimeoutException;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.reference.MessageId;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.services.monitor.ModuleControl;
import org.apache.derby.iapi.services.monitor.ModuleSupportable;
import org.apache.derby.iapi.services.monitor.Monitor;

import org.apache.derby.iapi.store.raw.RawStoreFactory;
import org.apache.derby.iapi.store.raw.log.LogFactory;
import org.apache.derby.iapi.store.raw.data.DataFactory;

import org.apache.derby.iapi.services.replication.master.MasterFactory;

import org.apache.derby.impl.services.replication.net.ReplicationMessage;
import org.apache.derby.impl.services.replication.ReplicationLogger;
import org.apache.derby.impl.services.replication.net.ReplicationMessageTransmit;
import org.apache.derby.impl.services.replication.buffer.ReplicationLogBuffer;
import org.apache.derby.impl.services.replication.buffer.LogBufferFullException;

import java.util.Properties;

/**
 * <p> 
 * This is an implementation of the replication master controller
 * service. The service is booted when this instance of Derby will
 * have the replication master role for this database.
 * </p> 
 * <p>
 * Note: The current version of the class is far from complete. Code
 * to control the replication master behavior will be added as more
 * parts of the replication functionality is added to Derby. 
 * </p>
 *
 * @see MasterFactory
 */
public class MasterController 
        implements MasterFactory, ModuleControl, ModuleSupportable {

    private static final int DEFAULT_LOG_BUFFER_SIZE = 32768; //32K

    private RawStoreFactory rawStoreFactory;
    private DataFactory dataFactory;
    private LogFactory logFactory;
    private ReplicationLogBuffer logBuffer;
    private AsynchronousLogShipper logShipper;
    private ReplicationMessageTransmit transmitter; 

    private String replicationMode;
    private String slavehost;
    private int slaveport;
    private String dbname;
    
    //Set to true when stopMaster is called
    private boolean stopMasterController = false;

    //How long to wait before reporting the failure to
    //establish a connection with the slave.
    // TODO: make this configurable through a property
    private static final int SLAVE_CONNECTION_ATTEMPT_TIMEOUT = 5000;


    /**
     * Empty constructor required by Monitor.bootServiceModule
     */
    public MasterController() { }

    ////////////////////////////////////////////////////////////
    // Implementation of methods from interface ModuleControl //
    ////////////////////////////////////////////////////////////

    /**
     * Used by Monitor.bootServiceModule to start the service. Will:
     *
     * Set up basic variables
     * Connect to the slave using the network service (DERBY-2921)
     *
     * Not implemented yet
     *
     * @param create Currently ignored
     * @param properties Properties used to start the service in the
     * correct mode
     * @exception StandardException Standard Derby exception policy,
     * thrown on error.
     */
    public void boot(boolean create, Properties properties)
        throws StandardException {

        replicationMode =
            properties.getProperty(MasterFactory.REPLICATION_MODE);

        slavehost = properties.getProperty(MasterFactory.SLAVE_HOST);

        String port = properties.getProperty(MasterFactory.SLAVE_PORT);
        if (port != null) {
            slaveport = new Integer(port).intValue();
        }

        dbname = properties.getProperty(MasterFactory.MASTER_DB);
    }

    ////////////////////////////////////////////////////////////////
    // Implementation of methods from interface ModuleSupportable //
    ////////////////////////////////////////////////////////////////

    /**
     * Used by Monitor.bootServiceModule to check if this class is
     * usable for replication. To be usable, we require that
     * asynchronous replication is specified in startParams by
     * checking that a property with key
     * MasterFactory.REPLICATION_MODE has the value
     * MasterFactory.ASYNCHRONOUS_MODE. 
     * @param startParams The properties used to boot replication
     * @return true if asynchronous replication is requested, meaning
     * that this MasterController is a suitable implementation for the
     * MasterFactory service. False otherwise
     * @see ModuleSupportable#canSupport 
     */
    public boolean canSupport(Properties startParams) {
        String modeParam =
            startParams.getProperty(MasterFactory.REPLICATION_MODE);

        // currently only one attribute: asynchronous replication mode
        if (modeParam != null && 
            modeParam.equals(MasterFactory.ASYNCHRONOUS_MODE)) {
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Will stop the replication master service
     *
     * Not implemented yet
     */
    public void stop() { }

    ////////////////////////////////////////////////////////////
    // Implementation of methods from interface MasterFactory //
    ////////////////////////////////////////////////////////////

    /**
     * Will perform all the work that is needed to set up replication.
     *
     * @param rawStore The RawStoreFactory for the database
     * @param dataFac The DataFactory for this database
     * @param logFac The LogFactory ensuring recoverability for this database
     * @exception StandardException Standard Derby exception policy,
     * thrown on replication startup error. 
     */
    public void startMaster(RawStoreFactory rawStore,
                            DataFactory dataFac, LogFactory logFac) 
                            throws StandardException {
        stopMasterController = false;
        rawStoreFactory = rawStore;
        dataFactory = dataFac;
        logFactory = logFac;
        logBuffer = new ReplicationLogBuffer(DEFAULT_LOG_BUFFER_SIZE, this);

        logFactory.startReplicationMasterRole(this);

        setupConnection();

        if (replicationMode.equals(MasterFactory.ASYNCHRONOUS_MODE)) {
            logShipper = new AsynchronousLogShipper(logBuffer,
                                                    transmitter,
                                                    this);
            ((Thread)logShipper).start();
        }

        // Add code that initializes replication by sending the
        // database to the slave, making logFactory add logrecords to
        // the buffer etc. Repliation should be up and running when
        // this method returns.

        Monitor.logTextMessage(MessageId.REPLICATION_MASTER_STARTED, dbname);
    }

    /**
     * Will perform all work that is needed to shut down replication<commit_msg>DERBY-3384: Replication: startMaster now unfreezes the database.  Contributed by Narayanan.<commit_after>/*
 
   Derby - Class
   org.apache.derby.impl.services.replication.master.MasterController
 
   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.derby.impl.services.replication.master;

import java.io.IOException;
import java.net.SocketTimeoutException;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.reference.MessageId;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.services.monitor.ModuleControl;
import org.apache.derby.iapi.services.monitor.ModuleSupportable;
import org.apache.derby.iapi.services.monitor.Monitor;

import org.apache.derby.iapi.store.raw.RawStoreFactory;
import org.apache.derby.iapi.store.raw.log.LogFactory;
import org.apache.derby.iapi.store.raw.data.DataFactory;

import org.apache.derby.iapi.services.replication.master.MasterFactory;

import org.apache.derby.impl.services.replication.net.ReplicationMessage;
import org.apache.derby.impl.services.replication.ReplicationLogger;
import org.apache.derby.impl.services.replication.net.ReplicationMessageTransmit;
import org.apache.derby.impl.services.replication.buffer.ReplicationLogBuffer;
import org.apache.derby.impl.services.replication.buffer.LogBufferFullException;

import java.util.Properties;

/**
 * <p> 
 * This is an implementation of the replication master controller
 * service. The service is booted when this instance of Derby will
 * have the replication master role for this database.
 * </p> 
 * <p>
 * Note: The current version of the class is far from complete. Code
 * to control the replication master behavior will be added as more
 * parts of the replication functionality is added to Derby. 
 * </p>
 *
 * @see MasterFactory
 */
public class MasterController 
        implements MasterFactory, ModuleControl, ModuleSupportable {

    private static final int DEFAULT_LOG_BUFFER_SIZE = 32768; //32K

    private RawStoreFactory rawStoreFactory;
    private DataFactory dataFactory;
    private LogFactory logFactory;
    private ReplicationLogBuffer logBuffer;
    private AsynchronousLogShipper logShipper;
    private ReplicationMessageTransmit transmitter; 

    private String replicationMode;
    private String slavehost;
    private int slaveport;
    private String dbname;
    
    //Set to true when stopMaster is called
    private boolean stopMasterController = false;

    //How long to wait before reporting the failure to
    //establish a connection with the slave.
    // TODO: make this configurable through a property
    private static final int SLAVE_CONNECTION_ATTEMPT_TIMEOUT = 5000;


    /**
     * Empty constructor required by Monitor.bootServiceModule
     */
    public MasterController() { }

    ////////////////////////////////////////////////////////////
    // Implementation of methods from interface ModuleControl //
    ////////////////////////////////////////////////////////////

    /**
     * Used by Monitor.bootServiceModule to start the service. Will:
     *
     * Set up basic variables
     * Connect to the slave using the network service (DERBY-2921)
     *
     * Not implemented yet
     *
     * @param create Currently ignored
     * @param properties Properties used to start the service in the
     * correct mode
     * @exception StandardException Standard Derby exception policy,
     * thrown on error.
     */
    public void boot(boolean create, Properties properties)
        throws StandardException {

        replicationMode =
            properties.getProperty(MasterFactory.REPLICATION_MODE);

        slavehost = properties.getProperty(MasterFactory.SLAVE_HOST);

        String port = properties.getProperty(MasterFactory.SLAVE_PORT);
        if (port != null) {
            slaveport = new Integer(port).intValue();
        }

        dbname = properties.getProperty(MasterFactory.MASTER_DB);
    }

    ////////////////////////////////////////////////////////////////
    // Implementation of methods from interface ModuleSupportable //
    ////////////////////////////////////////////////////////////////

    /**
     * Used by Monitor.bootServiceModule to check if this class is
     * usable for replication. To be usable, we require that
     * asynchronous replication is specified in startParams by
     * checking that a property with key
     * MasterFactory.REPLICATION_MODE has the value
     * MasterFactory.ASYNCHRONOUS_MODE. 
     * @param startParams The properties used to boot replication
     * @return true if asynchronous replication is requested, meaning
     * that this MasterController is a suitable implementation for the
     * MasterFactory service. False otherwise
     * @see ModuleSupportable#canSupport 
     */
    public boolean canSupport(Properties startParams) {
        String modeParam =
            startParams.getProperty(MasterFactory.REPLICATION_MODE);

        // currently only one attribute: asynchronous replication mode
        if (modeParam != null && 
            modeParam.equals(MasterFactory.ASYNCHRONOUS_MODE)) {
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Will stop the replication master service
     *
     * Not implemented yet
     */
    public void stop() { }

    ////////////////////////////////////////////////////////////
    // Implementation of methods from interface MasterFactory //
    ////////////////////////////////////////////////////////////

    /**
     * Will perform all the work that is needed to set up replication.
     *
     * @param rawStore The RawStoreFactory for the database
     * @param dataFac The DataFactory for this database
     * @param logFac The LogFactory ensuring recoverability for this database
     * @exception StandardException Standard Derby exception policy,
     * thrown on replication startup error. 
     */
    public void startMaster(RawStoreFactory rawStore,
                            DataFactory dataFac, LogFactory logFac) 
                            throws StandardException {
        stopMasterController = false;
        rawStoreFactory = rawStore;
        dataFactory = dataFac;
        logFactory = logFac;
        logBuffer = new ReplicationLogBuffer(DEFAULT_LOG_BUFFER_SIZE, this);

        logFactory.startReplicationMasterRole(this);
        
        rawStoreFactory.unfreeze();

        setupConnection();

        if (replicationMode.equals(MasterFactory.ASYNCHRONOUS_MODE)) {
            logShipper = new AsynchronousLogShipper(logBuffer,
                                                    transmitter,
                                                    this);
            ((Thread)logShipper).start();
        }

        // Add code that initializes replication by sending the
        // database to the slave, making logFactory add logrecords to
        // the buffer etc. Repliation should be up and running when
        // this method returns.

        Monitor.logTextMessage(MessageId.REPLICATION_MASTER_STARTED, dbname);
    }

    /**
     * Will perform all work that is needed to shut down replication
{'fraction_non_alphanumeric': 0.10881884750079593, 'fraction_numerical': 0.0026743075453677175, 'mean_word_length': 2.4270128736635392, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4673732', 'n_tokens_mistral': 3834, 'n_tokens_neox': 3654, 'n_words': 1255}