package codeine.db.mysql; import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.apache.log4j.Logger; import codeine.executer.PeriodicExecuter; import codeine.executer.Task; import codeine.jsons.global.MysqlConfigurationJson; import codeine.utils.ExceptionUtils; import com.google.common.base.Function; import com.google.common.collect.Lists; public class MysqlProcessControlService { private static final long MYSQL_CHECK_INTERVAL = TimeUnit.HOURS.toMillis(1); public static boolean CHECK_TABLE_INTEGRITY_ON_STARTUP = false; transient private static Logger log = Logger.getLogger(MysqlProcessControlService.class.getName()); private MXJController m_mysql = null; private MXJController m_slaveMysql = null; private MysqlProcessConfiguration m_conf = null; private String m_sSlavePath; @Inject private DbUtils dbUtils; @Inject private MysqlHostSelector mysqlHostSelector; public MysqlProcessControlService() { } public static void main(String[] args) { MysqlProcessControlService m = new MysqlProcessControlService(); m.config(); m.startServers(); } public void stopServers() { m_mysql.stop(); if (m_slaveMysql != null) { m_slaveMysql.stop(); } } public void config() { MysqlConfigurationJson mysqlConf = mysqlHostSelector.mysql(); String dir = mysqlConf.dir(); log.info("config() - path for persistency " + dir); if (new File(dir).mkdirs()) { log.info("config() - created directory " + dir); } if (m_sSlavePath == null) { m_mysql = new MXJController(dir, mysqlConf.port(), mysqlConf.bin_dir()); } else { m_mysql = new MXJController(dir, getFreePort(), mysqlConf.bin_dir()); m_mysql.setEnableBinaryLog(true); m_mysql.setServerID(1); m_slaveMysql = new MXJController(m_sSlavePath, getFreePort(), mysqlConf.bin_dir()); m_slaveMysql.setServerID(2); } if (null != m_conf) { m_mysql.addOptions(m_conf.getSqlOptions()); } System.setProperty("mysql.port", String.valueOf(m_mysql.getPort())); } // @Override // public String getSlavePath() // { // return m_slaveMysql == null ? null : m_slaveMysql.getBaseDir(); // } // // @Override // public void setConfiguration(MysqlProcessConfiguration conf) // { // m_conf = conf; // } // public static void main(String[] args) throws UnknownHostException { // System.out.println(InetUtils.getLocalHost().equals(InetAddress.getByName("itstl1058.iil.intel.com"))); // } private int getFreePort() { try { ServerSocket ssocket = new ServerSocket(0); int port = ssocket.getLocalPort(); ssocket.close(); return port; } catch (IOException e) { log.error("getFreePort() - I/O Exception", e); return 0; } } public void startServers() { startDatabase(); if (!m_mysql.isRunning()) { log.warn("mysqld PID not found, will attempt to restart mysqld"); m_mysql.stop(); startDatabase(); } } private void startDatabase() { startMysqlServer(); initDatabase(); chmodDBPermissions(); } private boolean initDatabase(){ MysqlConfigurationJson mysqlConf = mysqlHostSelector.mysql(); String sql = "SELECT user FROM mysql.user WHERE user='" + mysqlConf.user() + "'"; final List<String> result = Lists.newArrayList(); Function<ResultSet, Void> function = new Function<ResultSet, Void>() { @Override public Void apply(ResultSet rs) { try { result.add(rs.getString(1)); return null; } catch (SQLException e) { throw ExceptionUtils.asUnchecked(e); } } }; dbUtils.executeQueryAsRoot(sql, function); if (!result.isEmpty() && !(result.contains(mysqlConf.user()))) { log.info("createDbUser() - user already exists " + mysqlConf.user()); return true; } else { log.info("createDbUser() - creating user in database"); sql = "CREATE USER '" + mysqlConf.user() + "'@'%' identified by '" + MysqlConstants.DB_PASSWORD + "'"; int rs = dbUtils.executeUpdateAsRoot(sql); if (rs != -1) { log.info("user created successfully"); } sql = "GRANT ALL PRIVILEGES ON *.* TO '" + mysqlConf.user() + "'@'%' WITH GRANT OPTION"; rs = dbUtils.executeUpdateAsRoot(sql); if (rs != -1) { log.info("permissions for the user created successfully"); } return false; } } /** * change the database file permissions in the file system to make it * readable to group level (like all other files). By default, MySQL creates * it with user permissions only */ private void chmodDBPermissions() { // FileUtil.chmod(m_mysql.getDataDir(), "g+r", true); } // private void registerMysqlConnection() // { // DatabaseConnectionData.Builder builder = new // DatabaseConnectionData.Builder(DatabaseTypes.MYSQL_MXJ); // builder.setUsername(DatabaseConnectionData.DB_USER_NAME); // builder.setDatabaseName(DB_NAME); // ServiceLocator.serviceOf(IDBAccessService.class).createConnection(CONNECTION_ID, // builder.build()); // } private void startMysqlServer() { if (!m_mysql.start()) { throw new RuntimeException("Cannot start mysql"); } if (m_slaveMysql != null) { if (m_slaveMysql.start()) { try { // setupReplication(); } catch (Exception e) { log.error("Failed to set repolication", e); } } } } // private void setupReplication() throws SQLException // { // ReplicationSetupResult result = setupReplicationOnMaster(); // (new ReplicationCleanupTask()).startAfterWait(); // setupReplicationSlave(result.logFileName, result.logPosition); // } // // private class ReplicationSetupResult // { // public String logFileName; // public long logPosition; // } // private ReplicationSetupResult setupReplicationOnMaster() throws // SQLException // { // DatabaseConnectionData.Builder builder = new // DatabaseConnectionData.Builder(DatabaseTypes.MYSQL_MXJ); // builder.setUsername(DatabaseConnectionData.DB_SUPER_USER_NAME); // builder.setDatabaseName(null); // builder.setDatabasePort(m_mysql.getPort()); // IDatabaseConnectionManager dbconn = // ServiceLocator.serviceOf(IDBAccessService.class).createConnection(CONNECTION_ID, // builder.build()); // if(!dbconn.isConnected()) // { // log.error("Could not connect to database (2) check mysql log for more details " // + PersistencyData.getDataStoragePath() + "/data/mysql.out"); // throw new SQLException("Cannot connect to master DB"); // } // createDbUser(DB_REPLICATION_USER_NAME, "REPLICATION SLAVE"); // DbUtils.executeStatement("FLUSH TABLES WITH READ LOCK",CONNECTION_ID); // final ReplicationSetupResult result = new ReplicationSetupResult(); // Function<IDBRow,String> function = new Function<IDBRow,String>() // { // @Override // public String apply(IDBRow from) // { // result.logFileName = from.getString("File"); // result.logPosition = from.getLong("Position"); // return null; // } // }; // // ServiceLocator.serviceOf(IDBAccessService.class).executeQuery("SHOW MASTER STATUS", // CONNECTION_ID,function); // ServiceLocator.serviceOf(IDBAccessService.class).destroyConnection(CONNECTION_ID); // return result; // } // private void setupReplicationSlave(String logFileName, long // logFilePosition) throws SQLException // { // DatabaseConnectionData.Builder builder = new // DatabaseConnectionData.Builder(DatabaseTypes.MYSQL_MXJ); // builder.setUsername(DatabaseConnectionData.DB_SUPER_USER_NAME); // builder.setDatabaseName(null); // builder.setDatabasePort(m_slaveMysql.getPort()); // IDatabaseConnectionManager conn = // ServiceLocator.serviceOf(IDBAccessService.class).createConnection(CONNECTION_ID, // builder.build()); // if(conn==null) // { // log.error("Could not connect to database (2) check mysql log for more details " // + PersistencyData.getDataStoragePath() + "/data/mysql.out"); // throw new SQLException("Cannot connect to slave DB"); // } // DbUtils.executeStatement("STOP SLAVE", CONNECTION_ID); // createDbUser(DB_REPLICATION_USER_NAME, "REPLICATION SLAVE"); // DbUtils.executeStatement("CHANGE MASTER TO MASTER_HOST='localhost', MASTER_PORT=" // + m_mysql.getPort() + ", MASTER_USER='" + DB_REPLICATION_USER_NAME // + "', MASTER_LOG_FILE='" + logFileName + "', MASTER_LOG_POS=" + // logFilePosition, CONNECTION_ID); // DbUtils.executeStatement("START SLAVE", CONNECTION_ID); // ServiceLocator.serviceOf(IDBAccessService.class).destroyConnection(CONNECTION_ID); // } public void execute() { config(); startServers(); new PeriodicExecuter(MYSQL_CHECK_INTERVAL, new MySQLProcessMonitor(m_mysql), "mysql_monitor").runInThread(); } // private class ReplicationCleanupTask extends RecurringTask // { // // public ReplicationCleanupTask() // { // super(DB_REPLICATION_CLEANUP_MILLI); // } // // @Override // public boolean performTask(Object context) // { // try // { // log.info("replication logs cleaned up"); // DbUtils.executeStatement("RESET MASTER", CONNECTION_ID); // m_slaveMysql.cleanReplicationLogs(); // } // catch (SQLException e) // { // log.warn("cannot cleanup replication logs", e); // } // return true; // } // // @Override // public void onTaskFailure(Object context) // { // } // } private class MySQLProcessMonitor implements Task { private MXJController m_controller; MySQLProcessMonitor(MXJController controller) { super(); m_controller = controller; } private void check() { log.debug("checking if mysqld is running"); if (!m_controller.isRunning()) { log.warn("mysqld PID not found, will attempt to restart mysqld"); m_controller.stop(); startDatabase(); } } @Override public void run() { check(); } } }