package lsr.common; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.Marker; import org.slf4j.MarkerFactory; /** * Contains all the information describing the local process, including the * local id and the configuration of the system. * * @author Nuno Santos (LSR) */ public final class ProcessDescriptor { public final Configuration config; public final Marker logMark_Benchmark = MarkerFactory.getMarker("BENCHMARK"); public final Marker logMark_OldBenchmark = MarkerFactory.getMarker("OLD_BENCH"); /*--------------------------------------------- * The following properties are read from the * paxos.properties file *---------------------------------------------*/ /** * Defines the default window size - that is, the maximum number of * concurrently proposed instances. */ public static final String WINDOW_SIZE = "WindowSize"; public static final int DEFAULT_WINDOW_SIZE = 2; /** * Maximum UDP packet size in java is 65507. Higher than that and the send * method throws an exception. * * In practice, most networks have a lower limit on the maximum packet size * they can transmit. If this limit is exceeded, the lower layers will * usually fragment the packet, but in some cases there's a limit over which * large packets are simply dropped or raise an error. * * A safe value is the maximum ethernet frame: 1500 - maximum Ethernet * payload 20/40 - ipv4/6 header 8 - UDP header. * * Usually values up to 8KB are safe. */ public static final String MAX_UDP_PACKET_SIZE = "MaxUDPPacketSize"; public static final int DEFAULT_MAX_UDP_PACKET_SIZE = 8 * 1024; /** * Protocol to use between replicas. TCP, UDP or Generic, which combines * both */ public static final String NETWORK = "Network"; public static final String DEFAULT_NETWORK = "TCP"; /** * The maximum size of batched request. */ public static final String BATCH_SIZE = "BatchSize"; public static final int DEFAULT_BATCH_SIZE = 65507; /** How long to wait until suspecting the leader. In milliseconds */ public static final String FD_SUSPECT_TO = "FDSuspectTimeout"; public static final int DEFAULT_FD_SUSPECT_TO = 1000; /** Interval between sending heartbeats. In milliseconds */ public final static String FD_SEND_TO = "FDSendTimeout"; public static final int DEFAULT_FD_SEND_TO = 500; /** * The crash model used. For valid entries see {@link CrashModel} */ public static final String CRASH_MODEL = "CrashModel"; public static final CrashModel DEFAULT_CRASH_MODEL = CrashModel.FullSS; /** * Location of the stable storage (JPaxos logs) */ public static final String LOG_PATH = "LogPath"; public static final String DEFAULT_LOG_PATH = "jpaxosLogs"; /** * Maximum time in ms that a batch can be delayed before being proposed. * Used to aggregate several requests on a single proposal, for greater * efficiency. (Naggle's algorithm for state machine replication). */ public static final String MAX_BATCH_DELAY = "MaxBatchDelay"; public static final int DEFAULT_MAX_BATCH_DELAY = 10; public static final String CLIENT_ID_GENERATOR = "ClientIDGenerator"; public static final String DEFAULT_CLIENT_ID_GENERATOR = "TimeBased"; /** Enable or disable collecting of statistics */ public static final String BENCHMARK_RUN_REPLICA = "BenchmarkRunReplica"; public static final boolean DEFAULT_BENCHMARK_RUN_REPLICA = false; /** * Before any snapshot was made, we need to have an estimate of snapshot * size. Value given as for now is 1 KB */ public static final String FIRST_SNAPSHOT_SIZE_ESTIMATE = "FirstSnapshotEstimateBytes"; public static final int DEFAULT_FIRST_SNAPSHOT_SIZE_ESTIMATE = 1024; /** Minimum size of the log before a snapshot is attempted */ public static final String SNAPSHOT_MIN_LOG_SIZE = "MinLogSizeForRatioCheckBytes"; public static final int DEFAULT_SNAPSHOT_MIN_LOG_SIZE = 100 * 1024; /** Ratio = \frac{log}{snapshot}. How bigger the log must be to ask */ public static final String SNAPSHOT_ASK_RATIO = "SnapshotAskRatio"; public static final double DEFAULT_SNAPSHOT_ASK_RATIO = 1; /** Ratio = \frac{log}{snapshot}. How bigger the log must be to force */ public static final String SNAPSHOT_FORCE_RATIO = "SnapshotForceRatio"; public static final double DEFAULT_SNAPSHOT_FORCE_RATIO = 2; /** Minimum number of instances for checking ratios */ public static final String MIN_SNAPSHOT_SAMPLING = "MinimumInstancesForSnapshotRatioSample"; public static final int DEFAULT_MIN_SNAPSHOT_SAMPLING = 50; public static final String RETRANSMIT_TIMEOUT = "RetransmitTimeoutMilisecs"; public static final long DEFAULT_RETRANSMIT_TIMEOUT = 1000; /** If a TCP connection fails, how much to wait for another try */ public static final String TCP_RECONNECT_TIMEOUT = "TcpReconnectMilisecs"; public static final long DEFAULT_TCP_RECONNECT_TIMEOUT = 1000; /** ??? Corresponds to a ethernet frame */ public final static String FORWARD_MAX_BATCH_SIZE = "replica.ForwardMaxBatchSize"; public final static int DEFAULT_FORWARD_MAX_BATCH_SIZE = 1450; /** ??? In milliseconds */ public final static String FORWARD_MAX_BATCH_DELAY = "replica.ForwardMaxBatchDelay"; public final static int DEFAULT_FORWARD_MAX_BATCH_DELAY = 50; /** How many selector threads to use */ public static final String SELECTOR_THREADS = "replica.SelectorThreads"; public static final int DEFAULT_SELECTOR_THREADS = -1; /** * Size of a buffer for reading client requests; larger requests than this * size will cause extra memory allocation and freeing at each such request. * This variable impacts memory usage, as each client connection * pre-allocates such buffer. */ public static final String CLIENT_REQUEST_BUFFER_SIZE = "replica.ClientRequestBufferSize"; public static final int DEFAULT_CLIENT_REQUEST_BUFFER_SIZE = 8 * 1024 + ClientCommand.HEADERS_SIZE; /** * How long can the proposer / catch-up wait for batch values during view * change / catching up, in milliseconds */ private static final String MAX_BATCH_FETCHING_TIME_MS = "TimeoutFetchBatchValue"; private static final int DEFAULT_MAX_BATCH_FETCHING_TIME_MS = 2500; private static final String MULTICAST_PORT = "MulticastPort"; private static final int DEFAULT_MULTICAST_PORT = 3000; private static final String MULTICAST_IP_ADDRESS = "MulticastIpAddress"; private static final String DEFAULT_MULTICAST_IP_ADDRESS = "224.0.0.144"; private static final String MTU = "NetworkMtuSize"; private static final int DEFAULT_MTU = 1492; private static final String INDIRECT_CONSENSUS = "IndirectConsensus"; private static final boolean DEFAULT_INDIRECT_CONSENSUS = false; private static final String AUGMENTED_PAXOS = "AugmentedPaxos"; private static final boolean DEFAULT_AUGMENTED_PAXOS = false; /* * Exposing fields is generally not good practice, but here they are made * final, so there is no danger of exposing them. Advantage: less * boilerplate code. */ public final int localId; public final int numReplicas; public final int windowSize; public final int batchingLevel; public final int maxUdpPacketSize; public final int maxBatchDelay; public final String clientIDGenerator; public final String network; public final CrashModel crashModel; public final String logPath; public final int firstSnapshotSizeEstimate; public final int snapshotMinLogSize; public final double snapshotAskRatio; public final double snapshotForceRatio; public final int minSnapshotSampling; public final long retransmitTimeout; public final long tcpReconnectTimeout; public final int fdSuspectTimeout; public final int fdSendTimeout; public final int forwardBatchMaxSize; public final int forwardBatchMaxDelay; public final int selectorThreadCount; public final int clientRequestBufferSize; /** ⌊(n+1)/2⌋ */ public final int majority; public final long maxBatchFetchingTimeoutMs; public final int multicastPort; public final String multicastIpAddress; public final int mtu; public final boolean indirectConsensus; public final boolean augmentedPaxos; /** * The singleton instance of process descriptor. Must be initialized before * use. */ public static ProcessDescriptor processDescriptor = null; public static void initialize(Configuration config, int localId) { ProcessDescriptor.processDescriptor = new ProcessDescriptor(config, localId); } private ProcessDescriptor(Configuration config, int localId) { this.localId = localId; this.config = config; this.numReplicas = config.getN(); this.windowSize = config.getIntProperty( WINDOW_SIZE, DEFAULT_WINDOW_SIZE); this.batchingLevel = config.getIntProperty( BATCH_SIZE, DEFAULT_BATCH_SIZE); this.maxUdpPacketSize = config.getIntProperty( MAX_UDP_PACKET_SIZE, DEFAULT_MAX_UDP_PACKET_SIZE); this.maxBatchDelay = config.getIntProperty( MAX_BATCH_DELAY, DEFAULT_MAX_BATCH_DELAY); this.clientIDGenerator = config.getProperty( CLIENT_ID_GENERATOR, DEFAULT_CLIENT_ID_GENERATOR); this.network = config.getProperty( NETWORK, DEFAULT_NETWORK); this.logPath = config.getProperty( LOG_PATH, DEFAULT_LOG_PATH); this.firstSnapshotSizeEstimate = config.getIntProperty( FIRST_SNAPSHOT_SIZE_ESTIMATE, DEFAULT_FIRST_SNAPSHOT_SIZE_ESTIMATE); this.snapshotMinLogSize = Math.max(1, config.getIntProperty( SNAPSHOT_MIN_LOG_SIZE, DEFAULT_SNAPSHOT_MIN_LOG_SIZE)); this.snapshotAskRatio = config.getDoubleProperty( SNAPSHOT_ASK_RATIO, DEFAULT_SNAPSHOT_ASK_RATIO); this.snapshotForceRatio = config.getDoubleProperty( SNAPSHOT_FORCE_RATIO, DEFAULT_SNAPSHOT_FORCE_RATIO); this.minSnapshotSampling = config.getIntProperty( MIN_SNAPSHOT_SAMPLING, DEFAULT_MIN_SNAPSHOT_SAMPLING); this.retransmitTimeout = config.getLongProperty( RETRANSMIT_TIMEOUT, DEFAULT_RETRANSMIT_TIMEOUT); this.tcpReconnectTimeout = config.getLongProperty( TCP_RECONNECT_TIMEOUT, DEFAULT_TCP_RECONNECT_TIMEOUT); this.fdSuspectTimeout = config.getIntProperty( FD_SUSPECT_TO, DEFAULT_FD_SUSPECT_TO); this.fdSendTimeout = config.getIntProperty( FD_SEND_TO, DEFAULT_FD_SEND_TO); this.forwardBatchMaxDelay = config.getIntProperty( FORWARD_MAX_BATCH_DELAY, DEFAULT_FORWARD_MAX_BATCH_DELAY); this.forwardBatchMaxSize = config.getIntProperty(FORWARD_MAX_BATCH_SIZE, DEFAULT_FORWARD_MAX_BATCH_SIZE); this.selectorThreadCount = config.getIntProperty(SELECTOR_THREADS, DEFAULT_SELECTOR_THREADS); this.clientRequestBufferSize = config.getIntProperty( CLIENT_REQUEST_BUFFER_SIZE, DEFAULT_CLIENT_REQUEST_BUFFER_SIZE); this.maxBatchFetchingTimeoutMs = config.getIntProperty( MAX_BATCH_FETCHING_TIME_MS, DEFAULT_MAX_BATCH_FETCHING_TIME_MS); this.multicastPort = config.getIntProperty(MULTICAST_PORT, DEFAULT_MULTICAST_PORT); this.multicastIpAddress = config.getProperty(MULTICAST_IP_ADDRESS, DEFAULT_MULTICAST_IP_ADDRESS); this.mtu = config.getIntProperty(MTU, DEFAULT_MTU); this.indirectConsensus = config.getBooleanProperty(INDIRECT_CONSENSUS, DEFAULT_INDIRECT_CONSENSUS); this.augmentedPaxos = config.getBooleanProperty(AUGMENTED_PAXOS, DEFAULT_AUGMENTED_PAXOS); String crash = config.getProperty( CRASH_MODEL, DEFAULT_CRASH_MODEL.toString()); CrashModel crashModel; try { crashModel = CrashModel.valueOf(crash); } catch (IllegalArgumentException e) { throw new RuntimeException("Config file contains unknown crash model \"" + crash + "\""); } this.crashModel = crashModel; majority = (numReplicas + 1) / 2; printProcessDescriptor(config, crashModel); logMark_Benchmark.add(logMark_OldBenchmark); } private void printProcessDescriptor(Configuration config, CrashModel crashModel) { logger.info(config.toString()); logger.info(WINDOW_SIZE + "=" + windowSize); logger.info(BATCH_SIZE + "=" + batchingLevel); logger.info(MAX_BATCH_DELAY + "=" + maxBatchDelay); logger.info(MAX_UDP_PACKET_SIZE + "=" + maxUdpPacketSize); logger.info(NETWORK + "=" + network); logger.info(CLIENT_ID_GENERATOR + "=" + clientIDGenerator); logger.info(FD_SEND_TO + " = " + fdSendTimeout); logger.info(FD_SUSPECT_TO + "=" + fdSuspectTimeout); logger.info("Crash model: " + crashModel + ", LogPath: " + logPath); logger.info(FIRST_SNAPSHOT_SIZE_ESTIMATE + "=" + firstSnapshotSizeEstimate); logger.info(SNAPSHOT_MIN_LOG_SIZE + "=" + snapshotMinLogSize); logger.info(SNAPSHOT_ASK_RATIO + "=" + snapshotAskRatio); logger.info(SNAPSHOT_FORCE_RATIO + "=" + snapshotForceRatio); logger.info(MIN_SNAPSHOT_SAMPLING + "=" + minSnapshotSampling); logger.info(RETRANSMIT_TIMEOUT + "=" + retransmitTimeout); logger.info(TCP_RECONNECT_TIMEOUT + "=" + tcpReconnectTimeout); logger.info(FORWARD_MAX_BATCH_DELAY + "=" + forwardBatchMaxDelay); logger.info(FORWARD_MAX_BATCH_SIZE + "=" + forwardBatchMaxSize); logger.info(SELECTOR_THREADS + "=" + forwardBatchMaxSize); logger.info(CLIENT_REQUEST_BUFFER_SIZE + "=" + clientRequestBufferSize); logger.info(MAX_BATCH_FETCHING_TIME_MS + "=" + maxBatchFetchingTimeoutMs); logger.info(MULTICAST_PORT + "=" + multicastPort); logger.info(MULTICAST_IP_ADDRESS + "=" + multicastIpAddress); logger.info(MTU + "=" + mtu); } /** * @return the local process */ public PID getLocalProcess() { return config.getProcess(localId); } public int getLeaderOfView(int view) { return view % numReplicas; } public boolean isLocalProcessLeader(int view) { return getLeaderOfView(view) == localId; } private final static Logger logger = LoggerFactory.getLogger(ProcessDescriptor.class); /** * Next replica ID in lexical order, other than local replica. */ public int nextReplica(int nextReplicaToAsk) { nextReplicaToAsk++; nextReplicaToAsk %= numReplicas; if (nextReplicaToAsk == localId) { nextReplicaToAsk++; return nextReplicaToAsk % numReplicas; } return nextReplicaToAsk; } }