package org.apache.fullmatix.mysql; /* * 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. */ import org.apache.helix.NotificationContext; import org.apache.helix.model.Message; import org.apache.helix.participant.statemachine.StateModel; import org.apache.helix.participant.statemachine.StateModelInfo; import org.I0Itec.zkclient.DataUpdater; import org.apache.helix.HelixManager; import org.apache.helix.ZNRecord; import org.apache.helix.model.InstanceConfig; import org.apache.helix.participant.statemachine.Transition; import org.apache.log4j.Logger; @StateModelInfo(initialState = "OFFLINE", states = { "OFFLINE", "MASTER", "SLAVE" }) public class MasterSlaveTransitionHandler extends StateModel { private final class HighWaterMarkUpdater implements DataUpdater<ZNRecord> { private final Message message; private HighWaterMarkUpdater(Message message) { this.message = message; } @Override public ZNRecord update(ZNRecord currentData) { ZNRecord newRec = new ZNRecord(message.getResourceName()); if (currentData != null) { int currentGen = convertToInt(newRec.getSimpleField("currentGen"), 0); int currentGenStartSeq = convertToInt(newRec.getSimpleField("currentGenStartSeq"), 0); int prevGen = convertToInt(newRec.getSimpleField("prevGen"), 0); int prevGenEndSeq = convertToInt(newRec.getSimpleField("prevGenEndSeq"), 0); newRec.setSimpleField("currentGen", Integer.toString(currentGen + 1)); newRec.setSimpleField("currentGenStartSeq", Integer.toString(1)); if (currentGen > 0) { newRec.setSimpleField("prevGen", Integer.toString(currentGen)); int localEndSeq = 1; newRec.setSimpleField("prevGenEndSeq", "" + localEndSeq); } newRec.merge(currentData); } else { newRec.setSimpleField("currentGen", Integer.toString(1)); newRec.setSimpleField("currentGenStartSeq", Integer.toString(1)); } return newRec; } private int convertToInt(String number, int defaultValue) { try { if (number != null) { return Integer.parseInt(number); } } catch (Exception e) { } return defaultValue; } } private static Logger LOG = Logger.getLogger(MasterSlaveTransitionHandler.class); private final String _serverId; private final String _partition; private Replicator _replicator; private HelixManager _manager; public MasterSlaveTransitionHandler(Context context, String database, String partition) { _replicator = context.getReplicator(); _manager = context.getHelixManager(); String instanceName = _manager.getInstanceName(); _partition = partition; _serverId = instanceName; } /** * If the node is slave, start the rsync thread if it is not started * @param message * @param context * @throws Exception */ @Transition(from = "OFFLINE", to = "SLAVE") public void onBecomeSlaveFromOffline(Message message, NotificationContext context) throws Exception { LOG.info(_serverId + " transitioning from " + message.getFromState() + " to " + message.getToState() + " for " + _partition); //LOG.info("Creating database: " + _partition); // _mysqlAdmin.createDatabase(_partition); _replicator.initiateStart(); LOG.info(_serverId + " transitioned from " + message.getFromState() + " to " + message.getToState() + " for " + _partition); } /** * When the node becomes master, it will start accepting writes and increments * the epoch and starts logging the changes in a file * @param message * @param context * @throws Exception */ @Transition(from = "SLAVE", to = "MASTER") public void onBecomeMasterFromSlave(final Message message, NotificationContext context) throws Exception { _replicator.catchupAndStop(); LOG.info(_serverId + " transitioning from " + message.getFromState() + " to " + message.getToState() + " for " + _partition); /* * ZkHelixPropertyStore<ZNRecord> helixPropertyStore = * context.getManager().getHelixPropertyStore(); * String checkpointDirPath = instanceConfig.getRecord().getSimpleField("check_point_dir"); * DataUpdater<ZNRecord> updater = new HighWaterMarkUpdater(message); * helixPropertyStore.update( * "TRANSACTION_ID_METADATA" + "/" + message.getResourceName(), updater, * AccessOption.PERSISTENT); * Stat stat = new Stat(); * ZNRecord znRecord = * helixPropertyStore.get("TRANSACTION_ID_METADATA" + "/" * + message.getResourceName(), stat, AccessOption.PERSISTENT); * int startGen = Integer.parseInt(znRecord.getSimpleField("currentGen")); * int startSeq = Integer.parseInt(znRecord.getSimpleField("currentGenStartSeq")); * String fileStoreDir = instanceConfig.getRecord().getSimpleField("file_store_dir"); * String changeLogDir = instanceConfig.getRecord().getSimpleField("change_log_dir"); * // To indicate that we need callbacks for changes that happen starting now * long now = System.currentTimeMillis(); */ LOG.info(_serverId + " transitioned from " + message.getFromState() + " to " + message.getToState() + " for " + _partition); } /** * Stop writing * @param message * @param context * @throws Exception */ @Transition(from = "MASTER", to = "SLAVE") public void onBecomeSlaveFromMaster(Message message, NotificationContext context) throws Exception { LOG.info(_serverId + " transitioning from " + message.getFromState() + " to " + message.getToState() + " for " + _partition); _replicator.initiateStart(); } @Transition(from = "SLAVE", to = "OFFLINE") public void onBecomeOfflineFromSlave(Message message, NotificationContext context) { _replicator.initiateStop(); LOG.info(_serverId + " transitioning from " + message.getFromState() + " to " + message.getToState() + " for " + _partition); } public void onBecomeDroppedFromOffline(Message message, NotificationContext context) { LOG.info(_serverId + " Dropping partition " + _partition); } @Override public void reset() { LOG.warn("Default reset() invoked"); } }