/** * Copyright 2013-2015 Seagate Technology LLC. * * This Source Code Form is subject to the terms of the Mozilla * Public License, v. 2.0. If a copy of the MPL was not * distributed with this file, You can obtain one at * https://mozilla.org/MP:/2.0/. * * This program is distributed in the hope that it will be useful, * but is provided AS-IS, WITHOUT ANY WARRANTY; including without * the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or * FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public * License for more details. * * See www.openkinetic.org for more project information */ package kinetic.simulator; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import com.google.protobuf.ByteString; import com.seagate.kinetic.proto.Kinetic; import com.seagate.kinetic.proto.Kinetic.Command.GetLog.Configuration; import com.seagate.kinetic.simulator.heartbeat.HeartbeatProvider; import com.seagate.kinetic.simulator.heartbeat.provider.MulticastHeartbeatProvider; import com.seagate.kinetic.simulator.internal.SimulatorEngine; /** * * Simulator configuration instance. * */ public class SimulatorConfiguration extends Properties { private final static Logger logger = Logger .getLogger(SimulatorConfiguration.class.getName()); private static final long serialVersionUID = 1132514490479251740L; public final static String VENDER = "Seagate"; public final static String MODEL = "Simulator"; /** * Property name to set kinetic home folder directory under * <code>KINETIC_HOME</code> * <p> * The default is set to USER_HOME/kinetic directory if not set. * <p> * For example, /user/yourName/kinetic. */ public static final String KINETIC_HOME = "kinetic.home"; /** * Property name to set persist home folder directory under the * <code>KINETIC_HOME</code> folder. * * The default is set to leveldb.ldb under kinetic home folder. For example: * <p> * /user/yourName/kinetic/leveldb/leveldb.ldb * */ public static final String PERSIST_HOME = "kinetic.persist.home"; /** * server port. */ private int port = 8123; /** * use nio flag */ private volatile boolean useNio = true; /** * use ssl transport as default service. */ private final boolean useSslAsDefault = Boolean .getBoolean("kinetic.io.ssl"); /** * Start SSL transport service. */ private volatile boolean startSsl = (useSslAsDefault == false); /** * ssl service port. */ private int sslPort = 8443; /** * server nio thread pool exit await timeout in milli secs. */ private long threadPoolAwaitTimeout = 100; /** * default nio event loop threads */ private static final String DEFAULT_NIO_EVENT_LOOP_THREADS = "0"; /** * nio event loop boss threads */ private int nioEventLoopBossThreads = Integer .parseInt(DEFAULT_NIO_EVENT_LOOP_THREADS); /** * nio event loop worker threads */ private int nioEventLoopWorkerThreads = Integer .parseInt(DEFAULT_NIO_EVENT_LOOP_THREADS); /** * flag to indicate if memory store is used for the simulator */ private volatile boolean useMemoryStore = false; /** * heartbeat tick time in milli-seconds. */ private long tickTime = 5000; /** * heart beat destination address */ private String mcastDestination = "239.1.2.3"; /** * heart beat destination port */ private int mcastPort = 8123; /** * nio resource sharing flag for simulators running within the same JVM, * default is set to true. */ // private static boolean nioResourceSharing = Boolean // .getBoolean("kinetic.nio.resourceSharing"); private static boolean nioResourceSharing = true; /** * enforce command process ordering (in sequence) for messages received * within the same connection. */ // private boolean messageOrderinEnforced = Boolean // .getBoolean("kinetic.nio.messageOrder.enforced"); private boolean messageOrderinEnforced = true; /** * max supported value size in bytes */ private static int maxSupportedValueSize = 1024 * 1024; /** * max supported key size in bytes. */ private static int maxSupportedKeySize = 4096; /** * max supported version size in bytes */ private static int maxSupportedVersionSize = 2048; /** * max supported key range size. */ private static int maxSupportedKeyRangeSize = 200; /** * max supported tag size. -1 means not enforced (yet). */ private static int maxSupportedTagSize = -1; /** * max supported concurrent connections to the simulator. -1 means not * enforced (yet). */ private static int maxConnections = -1; /** * max supported outstanding read request. -1 means not enforced (yet). */ private static int maxOutstandingReadRequests = -1; /** * max supported outstanding write request. -1 means not enforced (yet). */ private static int maxOutstandingWriteRequests = -1; /** * max supported message size. -1 means not enforced (yet). */ private static int maxMessageSize = -1; /** * max supported identity cout. * * -1 means not enforced. */ private static int maxIdentityCount = -1; /** * max number of commands per batch. */ private static int maxCommandsPerBatch = 15; /** * max number of outstanding batch requests per drive. */ private static int maxOutstandingBatches = 5; /** * current simulator version. */ public static final String SIMULATOR_VERSION = "3.0.7-SNAPSHOT"; /** * simulator source commit hash. */ public static final String SIMULATOR_SOURCE_HASH = "4026da95012a74f137005362a419466dbcb2ae5a"; /** * current supported protocol version defined at kinetic-protocol * repository. */ public static final String PROTOCOL_VERSION = Kinetic.Local .getDefaultInstance().getProtocolVersion(); /** * current supported protocol source commit hash value obtained from * kinetic-protocol repository. */ public static final String PROTOCOL_SOURCE_HASH = "a5e192b2a42e2919ba3bba5916de8a2435f81243"; /** * heart beat provider. */ private HeartbeatProvider heartbeatProvider = null; /** * Serial number as a string */ private String serialNumber = null; /** * unique world wide name for each instance of simulator. */ private String worldWideName = null; /** * flag to indicate if the simulator should enforce connection Id * verification. if set to true, simulator will check and enforce that * client MUST set the assigned connection Id in all sub-sequential request * messages to the simulator/drive. * * The connection Id is set by drive/simulator in the first response message * after a connection is created. * * Default is set to false unless the * "kinetic.simulator.connection.id.enforced" system property is set to * true. * * Default will be set to true after the released drive code enforces the * verification. */ private static boolean isConnectionIdCheckEnforced = Boolean .getBoolean("kinetic.simulator.connection.id.enforced"); /** * Construct a server configuration instance with the specified defaults. * * @param props * default server configuration properties. */ public SimulatorConfiguration(Properties props) { super(props); init(); } /** * Construct a server configuration instance with the system properties as * defaults. * */ public SimulatorConfiguration() { super(System.getProperties()); init(); } /** * init states. */ private void init() { // init # of nio threads this.nioEventLoopBossThreads = Integer.parseInt(super.getProperty( "kinetic.nio.thread", DEFAULT_NIO_EVENT_LOOP_THREADS)); } /** * Set service port. * * @param port * server port. */ public void setPort(int port) { this.port = port; } /** * Get service port. * * @return server port. */ public int getPort() { return this.port; } /** * Set SSL service port. * * @param sslPort * SSL service port. * @see #startSsl */ public void setSslPort(int sslPort) { this.sslPort = sslPort; } /** * Get SSL service port. * * @return ssl service port. */ public int getSslPort() { return this.sslPort; } /** * Set start SSL/TLS service flag. * <p> * By default, the simulator is started with TCP (8123) and SSL (8443) * services. * <p> * If the parameter is set to true, application may also use * {@link #setSslPort(int)} to set SSL service port such that it is * different from the default SSL/TLS service port (8443). * <p> * Applications may define Java System Property "-Dkinetic.io.ssl=true" to * use SSL/TLS as the only (default) transport service. Applications should * avoid calling this method with parameter (flag) set to true when * "-Dkinetic.io.ssl=true" is already defined. * <p> * * @param flag * Set to false to disable SSL service. Default is set to true. * * @see #getUseSslAsDefault() * @see #setSslPort(int) */ public void setStartSsl(boolean flag) { this.startSsl = flag; } /** * Get start SSL service flag. * * @return true if start SSL flag is set to true. Otherwise, return false. */ public boolean getStartSsl() { return this.startSsl; } /** * Set use Java NIO or not. * * @param flag * set to true if use nio. Otherwise, set to false. The default * is set to true if not set. * */ public void setUseNio(boolean flag) { // XXX chiaming 07/19/2014: This will be re-enabled when it is // compatible with 3.0.0 logger.warning("Method is disabled., Only NIO is supported."); // this.useNio = flag; } /** * Get if the server uses Java NIO. * * @return true if the server uses Java NIO. Otherwise, return false. */ public boolean getUseNio() { return this.useNio; } /** * * Applications may define Java System Property "-Dkinetic.io.ssl=true" and * uses SSL/TLS as the default transport service. * <p> * * @return true if SSL/TLS is used as the default transport service. * Otherwise, return false. */ public boolean getUseSslAsDefault() { return this.useSslAsDefault; } /** * Get Java Nio thread pool exit await timeout - used when connection is * closed and Java client runtime library waiting for thread pool to exit. * * @return time out in milli seconds. */ public long getThreadPoolAwaitTimeout() { return this.threadPoolAwaitTimeout; } /** * Set Java Nio thread pool exit await timeout - used when connection is * closed and Java client runtime library waiting for thread pool to exit. * * @param millis * Java Nio thread pool exit await timeout in milli seconds */ public void setThreadPoolAwaitTimeOut(long millis) { this.threadPoolAwaitTimeout = millis; } /** * Get configuration property with the specified property name. * <p> * If there is a value set to the configuration, the value is returned. If * there is no value set to the configuration, the Simulator checks and * returns the value if Java System Property is defined for the property * name. */ @Override public String getProperty(String name) { String value = null; value = super.getProperty(name); if (value == null) { value = System.getProperty(name); } return value; } /** * Set nio service thread pool number for the simulator nio 'boss' (in-bound * connection) thread pool. * <p> * If not set, the default is set to 0 - the system will determine the * number based on available processors obtained from <code>Runtime</code> * API. * * @param nThreads * number of threads for simulator nio in-bound connection thread * pool. * * @see Runtime#availableProcessors() */ public void setNioServiceBossThreads(int nThreads) { if (nThreads < 0) { throw new java.lang.IllegalArgumentException( "nThread must be greater or equal to 0"); } this.nioEventLoopBossThreads = nThreads; } /** * Get nio thread number for the simulator nio service thread pool. * * @return nio threads number for the simulator nio service thread pool. */ public int getNioServiceBossThreads() { return this.nioEventLoopBossThreads; } /** * Set nio service thread pool number for the simulator nio 'worker' thread * pool. * <p> * If not set, the default is set to 0 - the system will determine the * number based on available processors obtained from <code>Runtime</code> * API. * * @param nThreads * number of threads for simulator nio worker thread pool. * * @see Runtime#availableProcessors() */ public void setNioServiceWorkerThreads(int nThreads) { if (nThreads < 0) { throw new java.lang.IllegalArgumentException( "nThread must be greater or equal to 0"); } this.nioEventLoopWorkerThreads = nThreads; } /** * Get nio thread number for the simulator nio service worker thread pool. * * @return nio threads number for the simulator nio service worker thread * pool. */ public int getNioServiceWorkerThreads() { return this.nioEventLoopWorkerThreads; } /** * Set to true to instruct the simulator to use memory store. * <p> * The default is set to false. LevelDB is used by default. * * @param useMemoryStore * set to true to instruct the simulator to use memory store. */ public void setUseMemoryStore(boolean useMemoryStore) { this.useMemoryStore = useMemoryStore; } /** * Get if memory store is (will be used) used by the simulator. * * @return true to use memory store. Otherwise, LevelDB is used. */ public boolean getUseMemoryStore() { return this.useMemoryStore; } /** * Set heart beat tick time for the simulator (in milli-seconds). * <p> * Default is set to 30000 milli-seconds. * * @param tickTime * heartbeat for the simulator. */ public void setTickTime(long tickTime) { if (this.tickTime < 0) { throw new java.lang.IllegalArgumentException( "tick time must be greater or equal to 0"); } this.tickTime = tickTime; } /** * Get heart beat tick time (in milli-seconds) for the simulator. * <p> * Default is set to 5000 milli-seconds. * * @return heart beat tick time for the simulator. */ public long getTickTime() { return this.tickTime; } /** * Set heart beat address for the simulator. The heart beat will be sent to * the specified multicast address and port. * * @param multicastAddress * heart beat address for the simulator. * * @see #setHeartBeatPort(int) */ public void setHeartbeatAddress(String multicastAddress) { this.mcastDestination = multicastAddress; } /** * Get heart beat address for the simulator. The heart beat will be sent to * the specified multicast address and port. * * @return heart beat address for the simulator. * * @see #setHeartBeatPort(int) */ public String getHeartbeatAddress() { return this.mcastDestination; } /** * Set heart beat destination port number. The heart beat will be sent to * the specified multicast address and port. * * @param multicastPort * heart beat destination port number. * * @see #setHeartbeatAddress(String) */ public void setHeartBeatPort(int multicastPort) { this.mcastPort = multicastPort; } /** * Get heart beat destination port number. The heart beat will be sent to * the specified multicast address and port. * * * @see #getHeartbeatAddress() * @return heart beat destination port number */ public int getHeartbeatPort() { return this.mcastPort; } /** * Set nio resource sharing flag. Set this flag to true to start a large * number of simulators (such as thousands) within the same JVM, depending * on the runtime operation system configuration. * * @param flag * if set to true, nio resources will be shared within the same * JVM for the simulator. */ public static void setNioResourceSharing(boolean flag) { nioResourceSharing = flag; } /** * Get nio resource sharing flag. If set to true, applications may be able * to start a large number of simulators (such as thousands) within the same * JVM, depending on the runtime operation system configuration. * * @return true if the simulators share nio resources. Otherwise return * false. */ public static boolean getNioResourceSharing() { return nioResourceSharing; } /** * Get if message is processed in received order within the same connection. * * @return true if message ordering is enforced. Otherwise, return false. */ public boolean getMessageOrderingEnforced() { return this.messageOrderinEnforced; } /** * * Set if message ordering should be enforced for the simulator. * <p> * This flag must be set before starting/instantiating the simulator. * * @param flag * set to true to instruct the simulator to enforce message * ordering within the same connection (a kinetic client * instance) */ public void setMessageOrderingEnforced(boolean flag) { this.messageOrderinEnforced = flag; } /** * Max supported value size in bytes. Default is set to 1M bytes (1024 * * 1024). * * @return max supported value size for the simulator. */ public static int getMaxSupportedValueSize() { return maxSupportedValueSize; } /** * Set max supported value size, in bytes. * * @param size * set max supported value size. * @see #getMaxSupportedValueSize() */ public static void setMaxSupportedValueSize(int size) { maxSupportedValueSize = size; } /** * Get max supported key size in bytes. Default is set to 4096 bytes. * * @return max supported key size for the simulator. */ public static int getMaxSupportedKeySize() { return maxSupportedKeySize; } /** * Set max supported key size, in bytes. * * @param size * set max supported key size. * @see #getMaxSupportedKeySize() */ public static void setMaxSupportedKeySize(int size) { maxSupportedKeySize = size; } /** * Get max supported version size in bytes. Default is set to 2048 bytes. * * @return max supported key size for the simulator. */ public static int getMaxSupportedVersionSize() { return maxSupportedVersionSize; } /** * Set max supported version size, in bytes. * * @param size * set max supported version size. * @see #getMaxSupportedVersionSize() */ public static void setMaxSupportedVersionSize(int size) { maxSupportedVersionSize = size; } /** * Get max supported key range size. Default is set to 1024. * * @return max supported key range size for the simulator. */ public static int getMaxSupportedKeyRangeSize() { return maxSupportedKeyRangeSize; } /** * Set max supported key range size, in bytes. * * @param size * set max supported key range size. */ public static void setMaxSupportedKeyRangeSize(int size) { maxSupportedKeyRangeSize = size; } /** * Get max supported concurrent connections. There is no enforcement for the * simulator at this time. * * Returns -1 means no limit is enforced for the current implementation. The * number will be adjusted when the limit is enforced. * * @return default value (-1) */ public static int getMaxConnections() { return maxConnections; } /** * Get max supported message size. There is no enforcement for the simulator * at this time. * * Returns -1 means no limit is enforced for the current implementation. The * number will be adjusted when the limit is enforced. * * @return default value (-1) */ public static int getMaxMessageSize() { return maxMessageSize; } /** * Get max outstanding read requests. There is no enforcement for the * simulator at this time. * * Returns -1 means no limit is enforced for the current implementation. The * number will be adjusted when the limit is enforced. * * @return default value (-1) */ public static int getMaxOutstandingReadRequests() { return maxOutstandingReadRequests; } /** * Get max outstanding write requests. There is no enforcement for the * simulator at this time. * * Returns -1 means no limit is enforced for the current implementation. The * number will be adjusted when the limit is enforced. * * @return default value (-1) */ public static int getMaxOutstandingWriteRequests() { return maxOutstandingWriteRequests; } /** * Get max supported tag size. There is no enforcement for the simulator at * this time. * * Returns -1 means no limit is enforced for the current implementation. The * number will be adjusted when the limit is enforced. * * @return default value (-1) */ public static int getMaxSupportedTagSize() { return maxSupportedTagSize; } /** * Get maximum identity count. * * Returns -1 means not enforced by the current implementation. * * @return default value (-1) */ public static int getMaxIdentityCount() { return maxIdentityCount; } /** * Get the current simulator version. * * @return current simulator version. */ public static String getSimulatorVersion() { return SIMULATOR_VERSION; } /** * Get the simulator source commit hash at he github repository. * * @return simulator source hash commit value * @see <a * href="https://github.com/Seagate/kinetic-protocol">kinetic-java</a> */ public static String getSimulatorSourceHash() { return SIMULATOR_SOURCE_HASH; } /** * Get Kinetic protocol version supported by the current API implementation. * The protocol version is defined at the kinetic-protocol repository. * <p> * <a * href="https://github.com/Seagate/kinetic-protocol">kinetic-protocol</a> * <p> * * @return Kinetic protocol version supported by the current API * implementation. * * @see <a * href="https://github.com/Seagate/kinetic-protocol">kinetic-protocol</a> */ public static String getProtocolVersion() { return PROTOCOL_VERSION; } /** * Get the supported protocol source commit hash at the kinetic-protocol * repository. * * @return protocol source commit hash value at the kinetic-protocol * repository. * * @see <a * href="https://github.com/Seagate/kinetic-protocol">kinetic-protocol</a> */ public static String getProtocolSourceHash() { return PROTOCOL_SOURCE_HASH; } /** * Set the heartbeat provider for the simulator. * * @param provider * provider to be used by the current instance of simulator */ public void setHeartbeatProvider(HeartbeatProvider provider) { this.heartbeatProvider = provider; } /** * Get heartbeat provider for the simulator instance. The * <code>MulticastHeartbeatProvider</code> is used if not set. * * @return the heartbeat provider for the simulator instance */ public HeartbeatProvider getHeartbeatProvider() { if (this.heartbeatProvider == null) { // use default multicast provider synchronized (this) { this.heartbeatProvider = new MulticastHeartbeatProvider(); } } return this.heartbeatProvider; } /** * Set if simulator should enforce connection Id verification. * * @param flag * set to true if simulator should enforce connection Id * verification. */ // public synchronized static void setIsConnectionIdCheckEnforced (boolean // flag) { // isConnectionIdCheckEnforced = flag; // } /** * Get flag that indicates if simulator is enforcing connection Id * verification. * * @return true if simulator is enforcing connection Id verification */ public static boolean getIsConnectionIdCheckEnforced() { return isConnectionIdCheckEnforced; } /** * Get simulator home folder name. * * @return simulator home folder name */ public String getSimulatorHome() { // get default String defaultHome = System.getProperty("user.home") + File.separator + "kinetic"; // use user defined home String kineticHome = getProperty(KINETIC_HOME, defaultHome); return kineticHome; } /** * Get the serial number of the running instance of simulator. * <p> * This number is to simulator a drive's serial number. * * @return the serial number of the running instance of simulator */ public String getSerialNumber() { if (this.worldWideName == null) { this.calculateWorldWideName(); } return this.serialNumber; } private synchronized void calculateWorldWideName() { if (this.worldWideName != null) { return; } try { // calculate kinetic home String khome = SimulatorEngine.kineticHome(this); // get wwn path String wwnFilePath = khome + File.separator + ".wwn"; // wwn file instance File wwnFile = new File(wwnFilePath); if (wwnFile.exists()) { /** * The file exists, get wwn from the content. */ FileInputStream in = new FileInputStream(wwnFile); // read contents Configuration conf = Configuration.parseFrom(in); in.close(); // get wwn ByteString ByteString wwn = conf.getWorldWideName(); // get wwn Java String type this.worldWideName = wwn.toStringUtf8(); // get serial number this.serialNumber = conf.getSerialNumber().toStringUtf8(); } else { // get UUID for this instance UUID uuid = UUID.randomUUID(); // wwn name this.worldWideName = uuid.toString(); // calculate serial number. this.serialNumber = "S" + Math.abs(worldWideName.hashCode()); /** * persist wwn/serial number. */ FileOutputStream out = new FileOutputStream(wwnFile); Configuration.Builder cb = Configuration.newBuilder(); // set serial number cb.setSerialNumber(ByteString.copyFromUtf8(this.serialNumber)); // set wwn cb.setWorldWideName(ByteString.copyFromUtf8(this.worldWideName)); // persist conf. cb.build().writeTo(out); out.close(); } } catch (Exception e) { this.worldWideName = "SIMULATOR-" + System.nanoTime(); this.serialNumber = "S" + Math.abs(worldWideName.hashCode()); logger.log(Level.WARNING, e.getMessage(), e); } finally { ; } } /** * Get world wide name of the running instance of the simulator. * * @return world wide name of the running instance of the simulato */ public String getWorldWideName() { if (this.worldWideName == null) { this.calculateWorldWideName(); } return this.worldWideName; } /** * Get maximum number of commands per batch request. * * @return maximum number of commands per batch request. */ public static int getMaxCommandsPerBatch() { return maxCommandsPerBatch; } /** * Get maximum number of outstanding batch requests per device. * * @return maximum number of outstanding batch requests per device. */ public static int getMaxOutstandingBatches() { return maxOutstandingBatches; } }