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

com.aoindustries.aoserv.client.FailoverFileReplication Maven / Gradle / Ivy

There is a newer version: 1.92.0
Show newest version
/*
 * aoserv-client - Java client for the AOServ platform.
 * Copyright (C) 2003-2013, 2015, 2016  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoserv-client.
 *
 * aoserv-client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aoserv-client 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with aoserv-client.  If not, see .
 */
package com.aoindustries.aoserv.client;

import com.aoindustries.aoserv.client.validator.HostAddress;
import com.aoindustries.aoserv.client.validator.InetAddress;
import com.aoindustries.aoserv.client.validator.ValidationException;
import com.aoindustries.io.BitRateProvider;
import com.aoindustries.io.CompressedDataInputStream;
import com.aoindustries.io.CompressedDataOutputStream;
import com.aoindustries.lang.ObjectUtils;
import com.aoindustries.util.BufferManager;
import com.aoindustries.util.InternUtils;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * Causes a server to replicate itself to another machine on a regular basis.
 *
 * @author  AO Industries, Inc.
 */
final public class FailoverFileReplication extends CachedObjectIntegerKey implements BitRateProvider {

	static final int COLUMN_PKEY=0;
	static final int COLUMN_SERVER=1;
	static final String COLUMN_SERVER_name = "server";
	static final String COLUMN_BACKUP_PARTITION_name = "backup_partition";

	int server;
	private int backup_partition;
	private Long max_bit_rate;
	private boolean use_compression;
	private short retention;
	private HostAddress connect_address;
	private InetAddress connect_from;
	private boolean enabled;
	private int quota_gid;

	public int addFailoverFileLog(long startTime, long endTime, int scanned, int updated, long bytes, boolean isSuccessful) throws IOException, SQLException {
		return table.connector.getFailoverFileLogs().addFailoverFileLog(this, startTime, endTime, scanned, updated, bytes, isSuccessful);
	}

	@Override
	public Long getBitRate() {
		return max_bit_rate;
	}

	public void setBitRate(Long bitRate) throws IOException, SQLException {
		table.connector.requestUpdateIL(true, AOServProtocol.CommandID.SET_FAILOVER_FILE_REPLICATION_BIT_RATE, pkey, bitRate==null ? -1 : bitRate);
	}

	@Override
	public int getBlockSize() {
		return BufferManager.BUFFER_SIZE;
	}

	@Override
	Object getColumnImpl(int i) {
		switch(i) {
			case COLUMN_PKEY: return pkey;
			case COLUMN_SERVER: return server;
			case 2: return backup_partition;
			case 3: return max_bit_rate;
			case 4: return use_compression;
			case 5: return retention;
			case 6: return connect_address;
			case 7: return connect_from;
			case 8: return enabled;
			case 9: return quota_gid==-1?null:quota_gid;
			default: throw new IllegalArgumentException("Invalid index: "+i);
		}
	}

	public List getFailoverFileSchedules() throws IOException, SQLException {
		return table.connector.getFailoverFileSchedules().getFailoverFileSchedules(this);
	}

	public Server getServer() throws SQLException, IOException {
		Server se=table.connector.getServers().get(server);
		if(se==null) throw new SQLException("Unable to find Server: "+server);
		return se;
	}

	/**
	 * May be filtered.
	 */
	public BackupPartition getBackupPartition() throws SQLException, IOException {
		return table.connector.getBackupPartitions().get(backup_partition);
	}

	/**
	 * Gets the most recent (by start time) log entries for failover file replications, up to the
	 * maximum number of rows.  May return less than this number of rows.  The results
	 * are sorted by start_time descending (most recent at index zero).
	 */
	public List getFailoverFileLogs(int maxRows) throws IOException, SQLException {
		return table.connector.getFailoverFileLogs().getFailoverFileLogs(this, maxRows);
	}

	public List getFailoverMySQLReplications() throws IOException, SQLException {
		return table.connector.getFailoverMySQLReplications().getFailoverMySQLReplications(this);
	}

	public boolean getUseCompression() {
		return use_compression;
	}

	public BackupRetention getRetention() throws SQLException, IOException {
		BackupRetention br=table.connector.getBackupRetentions().get(retention);
		if(br==null) throw new SQLException("Unable to find BackupRetention: "+retention);
		return br;
	}

	/**
	 * Gets a connect address that should override the normal address resolution mechanisms.  This allows
	 * a replication to be specifically sent through a gigabit connection or alternate route.
	 */
	public HostAddress getConnectAddress() {
		return connect_address;
	}

	/**
	 * Gets the address connections should be made from that overrides the normal address resolution mechanism.  This
	 * allows a replication to be specifically sent through a gigabit connection or alternate route.
	 */
	public InetAddress getConnectFrom() {
		return connect_from;
	}

	/**
	 * Gets the enabled flag for this replication.
	 */
	public boolean getEnabled() {
		return enabled;
	}

	/**
	 * When set, the group ID will always be set to this value, regardless what the client sends.
	 * This gid is only unique per backup_partition, thus on a single host the same gid
	 * may be used for different accounts.  Also, the gid will not exist in /etc/groups and has
	 * nothing to do with the shell accounts on the server.  This is to track quotas per backup
	 * partition by group ID.  This may only be set (and must be set) when stored on a
	 * backup_partition with quota_enabled.
	 */
	public LinuxID getQuotaGID() throws SQLException {
		if(quota_gid==-1) return null;
		LinuxID lid = table.connector.getLinuxIDs().get(quota_gid);
		if(lid==null) throw new SQLException("Unable to find LinuxID: "+quota_gid);
		return lid;
	}

	@Override
	public SchemaTable.TableID getTableID() {
		return SchemaTable.TableID.FAILOVER_FILE_REPLICATIONS;
	}

	@Override
	public void init(ResultSet result) throws SQLException {
		try {
			int pos = 1;
			pkey=result.getInt(pos++);
			server=result.getInt(pos++);
			backup_partition=result.getInt(pos++);
			long maxBitRateLong = result.getLong(pos++);
			max_bit_rate = result.wasNull() ? null : maxBitRateLong;
			use_compression=result.getBoolean(pos++);
			retention=result.getShort(pos++);
			connect_address=HostAddress.valueOf(result.getString(pos++));
			connect_from=InetAddress.valueOf(result.getString(pos++));
			enabled=result.getBoolean(pos++);
			quota_gid=result.getInt(pos++);
			if(result.wasNull()) quota_gid=-1;
		} catch(ValidationException e) {
			throw new SQLException(e);
		}
	}

	@Override
	public void read(CompressedDataInputStream in) throws IOException {
		try {
			pkey=in.readCompressedInt();
			server=in.readCompressedInt();
			backup_partition=in.readCompressedInt();
			long maxBitRateLong = in.readLong();
			max_bit_rate = maxBitRateLong==-1 ? null : maxBitRateLong;
			use_compression=in.readBoolean();
			retention=in.readShort();
			connect_address=InternUtils.intern(HostAddress.valueOf(in.readNullUTF()));
			connect_from=InternUtils.intern(InetAddress.valueOf(in.readNullUTF()));
			enabled=in.readBoolean();
			quota_gid=in.readCompressedInt();
		} catch(ValidationException e) {
			throw new IOException(e);
		}
	}

	@Override
	String toStringImpl() throws SQLException, IOException {
		return getServer().toStringImpl()+"->"+getBackupPartition().toStringImpl();
	}

	@Override
	public void write(CompressedDataOutputStream out, AOServProtocol.Version version) throws IOException {
		out.writeCompressedInt(pkey);
		out.writeCompressedInt(server);
		if(version.compareTo(AOServProtocol.Version.VERSION_1_30)<=0) out.writeCompressedInt(149); // to_server (hard-coded xen2.mob.aoindustries.com)
		if(version.compareTo(AOServProtocol.Version.VERSION_1_31)>=0) out.writeCompressedInt(backup_partition);
		if(
			version.compareTo(AOServProtocol.Version.VERSION_1_0_A_105)>=0
			&& version.compareTo(AOServProtocol.Version.VERSION_1_61)<=0
		) {
			int maxBitRateInt;
			if(max_bit_rate==null) maxBitRateInt = -1;
			else if(max_bit_rate>Integer.MAX_VALUE) maxBitRateInt = Integer.MAX_VALUE;
			else if(max_bit_rate<0) throw new IOException("Illegal bit rate: " + max_bit_rate);
			else maxBitRateInt = max_bit_rate.intValue();
			out.writeInt(maxBitRateInt);
		} else if(version.compareTo(AOServProtocol.Version.VERSION_1_62)>=0) {
			out.writeLong(max_bit_rate==null ? -1 : max_bit_rate);
		}
		if(version.compareTo(AOServProtocol.Version.VERSION_1_30)<=0) out.writeLong(-1); // last_start_time
		if(version.compareTo(AOServProtocol.Version.VERSION_1_9)>=0) out.writeBoolean(use_compression);
		if(version.compareTo(AOServProtocol.Version.VERSION_1_13)>=0) out.writeShort(retention);
		if(version.compareTo(AOServProtocol.Version.VERSION_1_14)>=0) out.writeNullUTF(ObjectUtils.toString(connect_address));
		if(version.compareTo(AOServProtocol.Version.VERSION_1_22)>=0) out.writeNullUTF(ObjectUtils.toString(connect_from));
		if(version.compareTo(AOServProtocol.Version.VERSION_1_15)>=0) out.writeBoolean(enabled);
		if(
			version.compareTo(AOServProtocol.Version.VERSION_1_17)>=0
			&& version.compareTo(AOServProtocol.Version.VERSION_1_30)<=0
		) {
			out.writeUTF("/var/backup"); // to_path (hard-coded /var/backup like found on xen2.mob.aoindustries.com)
			out.writeBoolean(false); // chunk_always
		}
		if(version.compareTo(AOServProtocol.Version.VERSION_1_31)>=0) out.writeCompressedInt(quota_gid);
	}

	public int addFileBackupSetting(String path, boolean backupEnabled, boolean required) throws IOException, SQLException {
		return table.connector.getFileBackupSettings().addFileBackupSetting(this, path, backupEnabled, required);
	}

	public FileBackupSetting getFileBackupSetting(String path) throws IOException, SQLException {
		return table.connector.getFileBackupSettings().getFileBackupSetting(this, path);
	}

	public List getFileBackupSettings() throws IOException, SQLException {
		return table.connector.getFileBackupSettings().getFileBackupSettings(this);
	}

	public void setFailoverFileSchedules(List hours, List minutes) throws IOException, SQLException {
		table.connector.getFailoverFileSchedules().setFailoverFileSchedules(this, hours, minutes);
	}

	public void setFileBackupSettings(List paths, List backupEnableds, List requireds) throws IOException, SQLException {
		table.connector.getFileBackupSettings().setFileBackupSettings(this, paths, backupEnableds, requireds);
	}

	public AOServer.DaemonAccess requestReplicationDaemonAccess() throws IOException, SQLException {
		return table.connector.requestResult(
			true,
			new AOServConnector.ResultRequest() {
				private AOServer.DaemonAccess daemonAccess;

				@Override
				public void writeRequest(CompressedDataOutputStream out) throws IOException {
					out.writeCompressedInt(AOServProtocol.CommandID.REQUEST_REPLICATION_DAEMON_ACCESS.ordinal());
					out.writeCompressedInt(pkey);
				}

				@Override
				public void readResponse(CompressedDataInputStream in) throws IOException, SQLException {
					int code=in.readByte();
					if(code==AOServProtocol.DONE) {
						try {
							daemonAccess = new AOServer.DaemonAccess(
								in.readUTF(),
								HostAddress.valueOf(in.readUTF()),
								in.readCompressedInt(),
								in.readLong()
							);
						} catch(ValidationException e) {
							throw new IOException(e);
						}
					} else {
						AOServProtocol.checkResult(code, in);
						throw new IOException("Unexpected response code: "+code);
					}
				}

				@Override
				public AOServer.DaemonAccess afterRelease() {
					return daemonAccess;
				}
			}
		);
	}

	public static class Activity {
		private final long timeSince;
		private final String message;

		private Activity(long timeSince, String message) {
			this.timeSince = timeSince;
			this.message = message;
		}

		/**
		 * Gets the amount of time since the activity was logged or -1 if no activity.
		 */
		public long getTimeSince() {
			return timeSince;
		}

		/**
		 * Gets the message for the activity or "" if no activity.
		 */
		public String getMessage() {
			return message;
		}
	}

	public Activity getActivity() throws IOException, SQLException {
		return table.connector.requestResult(
			true,
			new AOServConnector.ResultRequest() {
				Activity activity;

				@Override
				public void writeRequest(CompressedDataOutputStream out) throws IOException {
					out.writeCompressedInt(AOServProtocol.CommandID.GET_FAILOVER_FILE_REPLICATION_ACTIVITY.ordinal());
					out.writeCompressedInt(pkey);
				}

				@Override
				public void readResponse(CompressedDataInputStream in) throws IOException, SQLException {
					int code=in.readByte();
					if(code==AOServProtocol.DONE) {
						activity = new Activity(
							in.readLong(),
							in.readUTF()
						);
					} else {
						AOServProtocol.checkResult(code, in);
						throw new IOException("Unexpected response code: "+code);
					}
				}

				@Override
				public Activity afterRelease() {
					return activity;
				}
			}
		);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy