| /*- |
| * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved. |
| * |
| * This file was distributed by Oracle as part of a version of Oracle Berkeley |
| * DB Java Edition made available at: |
| * |
| * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html |
| * |
| * Please see the LICENSE file included in the top-level directory of the |
| * appropriate version of Oracle Berkeley DB Java Edition for a copy of the |
| * license and additional information. |
| */ |
| |
| package com.sleepycat.je; |
| |
| import java.util.StringTokenizer; |
| |
| /** |
| * Durability defines the overall durability characteristics associated with a |
| * transaction. When operating on a local environment the durability of a |
| * transaction is completely determined by the local {@link SyncPolicy} that is |
| * in effect. When using replication, the overall durability is a function of |
| * the local {@link SyncPolicy} plus the {@link ReplicaAckPolicy} used by the |
| * master and the {@link SyncPolicy} in effect at each Replica. |
| */ |
| public class Durability { |
| |
| /** |
| * A convenience constant that defines a durability policy with COMMIT_SYNC |
| * for local commit synchronization. |
| * |
| * The replicated environment policies default to COMMIT_NO_SYNC for |
| * commits of replicated transactions that need acknowledgment and |
| * SIMPLE_MAJORITY for the acknowledgment policy. |
| */ |
| public static final Durability COMMIT_SYNC = |
| new Durability(SyncPolicy.SYNC, // localSync |
| SyncPolicy.NO_SYNC, // replicaSync |
| ReplicaAckPolicy.SIMPLE_MAJORITY); // replicaAck |
| |
| /** |
| * A convenience constant that defines a durability policy with |
| * COMMIT_NO_SYNC for local commit synchronization. |
| * |
| * The replicated environment policies default to COMMIT_NO_SYNC for |
| * commits of replicated transactions that need acknowledgment and |
| * SIMPLE_MAJORITY for the acknowledgment policy. |
| */ |
| public static final Durability COMMIT_NO_SYNC = |
| new Durability(SyncPolicy.NO_SYNC, // localSync |
| SyncPolicy.NO_SYNC, // replicaSync |
| ReplicaAckPolicy.SIMPLE_MAJORITY); // replicaAck |
| |
| /** |
| * A convenience constant that defines a durability policy with |
| * COMMIT_WRITE_NO_SYNC for local commit synchronization. |
| * |
| * The replicated environment policies default to COMMIT_NO_SYNC for |
| * commits of replicated transactions that need acknowledgment and |
| * SIMPLE_MAJORITY for the acknowledgment policy. |
| */ |
| public static final Durability COMMIT_WRITE_NO_SYNC = |
| new Durability(SyncPolicy.WRITE_NO_SYNC,// localSync |
| SyncPolicy.NO_SYNC, // replicaSync |
| ReplicaAckPolicy.SIMPLE_MAJORITY); // replicaAck |
| |
| /** |
| * A convenience constant that defines a durability policy, with |
| * <code>ReplicaAckPolicy.NONE</code> for use with a read only transaction. |
| * A read only transaction on a Master, using this Durability, will thus |
| * not be held up, or throw <code>InsufficientReplicasException</code>, if |
| * the Master is not in contact with a sufficient number of Replicas at the |
| * time the transaction was initiated. <p> |
| * |
| * It's worth noting that since the transaction is read only, the sync |
| * policies, although specified as <code>NO_SYNC</code>, do not really |
| * matter. |
| * |
| * @deprecated use {@link TransactionConfig#setReadOnly} instead. |
| */ |
| public static final Durability READ_ONLY_TXN = |
| new Durability(SyncPolicy.NO_SYNC, // localSync |
| SyncPolicy.NO_SYNC, // replicaSync |
| ReplicaAckPolicy.NONE); // replicaAck |
| |
| /** |
| * Defines the synchronization policy to be used when committing a |
| * transaction. High levels of synchronization offer a greater guarantee |
| * that the transaction is persistent to disk, but trade that off for |
| * lower performance. |
| */ |
| public enum SyncPolicy { |
| |
| /** |
| * Write and synchronously flush the log on transaction commit. |
| * Transactions exhibit all the ACID (atomicity, consistency, |
| * isolation, and durability) properties. |
| * <p> |
| * This is the default for a non-replicated environment. |
| * |
| * @see <a href="EnvironmentStats.html#logFsync">I/O Statistics: |
| * Fsync and Group Commit</a> |
| */ |
| SYNC, |
| |
| /** |
| * Do not write or synchronously flush the log on transaction commit. |
| * Transactions exhibit the ACI (atomicity, consistency, and isolation) |
| * properties, but not D (durability); that is, database integrity will |
| * be maintained, but if the application or system fails, it is |
| * possible some number of the most recently committed transactions may |
| * be undone during recovery. The number of transactions at risk is |
| * governed by how many log updates can fit into the log buffer, how |
| * often the operating system flushes dirty buffers to disk, and how |
| * often the log is checkpointed. |
| * <p> |
| * This is the default for a replicated environment. |
| * |
| * @see <a href="EnvironmentStats.html#logBuffer">I/O Statistics: Log |
| * Buffers</a> |
| * |
| * @see <a href="EnvironmentStats.html#logWriteQueue">I/O Statistics: |
| * The Write Queue</a> |
| */ |
| NO_SYNC, |
| |
| /** |
| * Write but do not synchronously flush the log on transaction commit. |
| * Transactions exhibit the ACI (atomicity, consistency, and isolation) |
| * properties, but not D (durability); that is, database integrity will |
| * be maintained, but if the operating system fails, it is possible |
| * some number of the most recently committed transactions may be |
| * undone during recovery. The number of transactions at risk is |
| * governed by how often the operating system flushes dirty buffers to |
| * disk, and how often the log is checkpointed. |
| * |
| * @see <a href="EnvironmentStats.html#logFsync">I/O Statistics: |
| * Fsync and Group Commit</a> |
| */ |
| WRITE_NO_SYNC |
| }; |
| |
| /** |
| * A replicated environment makes it possible to increase an application's |
| * transaction commit guarantees by committing changes to its replicas on |
| * the network. ReplicaAckPolicy defines the policy for how such network |
| * commits are handled. |
| * <p> |
| * The choice of a ReplicaAckPolicy must be consistent across all the |
| * replicas in a replication group, to ensure that the policy is |
| * consistently enforced in the event of an election. |
| * |
| * <p>Note that SECONDARY nodes are not included in the set of replicas |
| * that must acknowledge transaction commits. |
| */ |
| public enum ReplicaAckPolicy { |
| |
| /** |
| * All ELECTABLE replicas must acknowledge that they have committed the |
| * transaction. This policy should be selected only if your replication |
| * group has a small number of ELECTABLE replicas, and those replicas |
| * are on extremely reliable networks and servers. |
| */ |
| ALL, |
| |
| /** |
| * No transaction commit acknowledgments are required and the master |
| * will never wait for replica acknowledgments. In this case, |
| * transaction durability is determined entirely by the type of commit |
| * that is being performed on the master. |
| */ |
| NONE, |
| |
| /** |
| * A simple majority of ELECTABLE replicas must acknowledge that they |
| * have committed the transaction. This acknowledgment policy, in |
| * conjunction with an election policy which requires at least a simple |
| * majority, ensures that the changes made by the transaction remains |
| * durable if a new election is held. |
| * <p> |
| * This is the default. |
| */ |
| SIMPLE_MAJORITY; |
| |
| /** |
| * Returns the minimum number of ELECTABLE replicas required to |
| * implement the ReplicaAckPolicy for a given replication group size. |
| * |
| * @param groupSize the number of ELECTABLE replicas in the replication |
| * group |
| * |
| * @return the number of ELECTABLE replicas needed |
| */ |
| public int minAckNodes(int groupSize) { |
| switch (this) { |
| case ALL: |
| return groupSize; |
| case NONE: |
| return 1; |
| case SIMPLE_MAJORITY: |
| return (groupSize / 2 + 1); |
| default: |
| throw EnvironmentFailureException.unexpectedState |
| ("Unknown ack policy: " + this); |
| } |
| } |
| } |
| |
| /* The sync policy in effect on the local node. */ |
| private final SyncPolicy localSync; |
| |
| /* The sync policy in effect on a replica. */ |
| final private SyncPolicy replicaSync; |
| |
| /* The replica acknowledgment policy to be used. */ |
| final private ReplicaAckPolicy replicaAck; |
| |
| /** |
| * Creates an instance of a Durability specification. |
| * |
| * @param localSync the SyncPolicy to be used when committing the |
| * transaction locally. |
| * @param replicaSync the SyncPolicy to be used remotely, as part of a |
| * transaction acknowledgment, at a Replica node. |
| * @param replicaAck the acknowledgment policy used when obtaining |
| * transaction acknowledgments from Replicas. |
| */ |
| public Durability(SyncPolicy localSync, |
| SyncPolicy replicaSync, |
| ReplicaAckPolicy replicaAck) { |
| this.localSync = localSync; |
| this.replicaSync = replicaSync; |
| this.replicaAck = replicaAck; |
| } |
| |
| /** |
| * Parses the string and returns the durability it represents. The string |
| * must have the following format: |
| * <p> |
| * <code> |
| * <i>SyncPolicy</i>[,<i>SyncPolicy</i>[,<i>ReplicaAckPolicy</i>]] |
| * </code> |
| * <p> |
| * The first SyncPolicy in the above format applies to the Master, and the |
| * optional second SyncPolicy to the replica. Specific SyncPolicy or |
| * ReplicaAckPolicy values are denoted by the name of the enumeration |
| * value. |
| * <p> |
| * For example, the string:<i>sync,sync,quorum</i> describes a durability |
| * policy where the master and replica both use {@link SyncPolicy#SYNC} |
| * to commit transactions and {@link ReplicaAckPolicy#SIMPLE_MAJORITY} to |
| * acknowledge a transaction commit. |
| * <p> |
| * {@link SyncPolicy#NO_SYNC}, is the default value for a node's |
| * SyncPolicy. |
| * <p> |
| * {@link ReplicaAckPolicy#SIMPLE_MAJORITY} is the default for the |
| * ReplicaAckPolicy. |
| * |
| * @param durabilityString the durability string in the above format |
| * |
| * @return the Durability resulting from the parse, or null if the |
| * <code>durabilityString</code> argument was itself null. |
| * |
| * @throws IllegalArgumentException if the durabilityString is invalid. |
| */ |
| public static Durability parse(String durabilityString) { |
| if (durabilityString == null) { |
| return null; |
| } |
| StringTokenizer tokenizer = |
| new StringTokenizer(durabilityString.toUpperCase(), ","); |
| |
| if (!tokenizer.hasMoreTokens()) { |
| throw new IllegalArgumentException |
| ("Bad string format: " + '"' + durabilityString + '"'); |
| } |
| SyncPolicy localSync = |
| SyncPolicy.valueOf(tokenizer.nextToken()); |
| SyncPolicy replicaSync = tokenizer.hasMoreTokens() ? |
| SyncPolicy.valueOf(tokenizer.nextToken()) : |
| SyncPolicy.NO_SYNC; |
| ReplicaAckPolicy replicaAck = tokenizer.hasMoreTokens() ? |
| ReplicaAckPolicy.valueOf(tokenizer.nextToken()) : |
| ReplicaAckPolicy.SIMPLE_MAJORITY; |
| return new Durability(localSync, replicaSync, replicaAck); |
| } |
| |
| /** |
| * Returns the string representation of durability in the format defined |
| * by string form of the Durability constructor. |
| * |
| * @see #parse(String) |
| */ |
| @Override |
| public String toString() { |
| return localSync.toString() + "," + |
| replicaSync.toString() + "," + |
| replicaAck.toString(); |
| } |
| |
| /** |
| * Returns the transaction synchronization policy to be used locally when |
| * committing a transaction. |
| */ |
| public SyncPolicy getLocalSync() { |
| return localSync; |
| } |
| |
| /** |
| * Returns the transaction synchronization policy to be used by the replica |
| * as it replays a transaction that needs an acknowledgment. |
| */ |
| public SyncPolicy getReplicaSync() { |
| return replicaSync; |
| } |
| |
| /** |
| * Returns the replica acknowledgment policy used by the master when |
| * committing changes to a replicated environment. |
| */ |
| public ReplicaAckPolicy getReplicaAck() { |
| return replicaAck; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result |
| + ((localSync == null) ? 0 : localSync.hashCode()); |
| result = prime * result |
| + ((replicaAck == null) ? 0 : replicaAck.hashCode()); |
| result = prime * result |
| + ((replicaSync == null) ? 0 : replicaSync.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (!(obj instanceof Durability)) { |
| return false; |
| } |
| Durability other = (Durability) obj; |
| if (localSync == null) { |
| if (other.localSync != null) { |
| return false; |
| } |
| } else if (!localSync.equals(other.localSync)) { |
| return false; |
| } |
| if (replicaAck == null) { |
| if (other.replicaAck != null) { |
| return false; |
| } |
| } else if (!replicaAck.equals(other.replicaAck)) { |
| return false; |
| } |
| if (replicaSync == null) { |
| if (other.replicaSync != null) { |
| return false; |
| } |
| } else if (!replicaSync.equals(other.replicaSync)) { |
| return false; |
| } |
| return true; |
| } |
| } |