/*
* Bitronix Transaction Manager
*
* Copyright (c) 2011, Juergen Kellerer.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package bitronix.tm.journal.nio;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.lang.Boolean.parseBoolean;
import static java.lang.Double.parseDouble;
import static java.lang.Integer.getInteger;
import static java.lang.Long.getLong;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.System.getProperty;
import static java.nio.charset.Charset.forName;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableSet;
import static java.util.concurrent.TimeUnit.SECONDS;
import static javax.transaction.Status.*;
/**
* Collection of 'runtime' constants and low level tuning options used by the nio journal implementation.
* <p/>
* Note: The tuning options contained in this interface are meant for usage by experts only. If one of the
* options turns out to be useful for the day to day configuration it will be moved into the main Configuration
* instance.
*
* @author juergen kellerer, 2011-04-30
*/
public interface NioJournalConstants {
/**
* The amount of milliseconds for one hour.
*/
long MS_PER_HOUR = 60 * 60 * 1000L;
/**
* The amount of milliseconds for one day.
*/
long MS_PER_DAY = 24 * MS_PER_HOUR;
/**
* Is the charset used for unique names and for human readable content in the headers.
* Important: must be a charset of constant size, using 8 bit encoding and be able to cover US-ASCII.
*/
Charset NAME_CHARSET = forName("ISO-8859-1");
// ---- SNIPPET-START: NioJournalTuningOptions
/**
* Max time to delay writes if force is not requested and queues have remaining capacity.
* <p/>
* Lowers the overall IO operations by combining write requests. This improves the overall
* system performance in medium load situations as more resources remain available to other
* services.
*/
long WRITE_DELAY = getLong("bitronix.nio.journal.write.delay", SECONDS.toMillis(2));
/**
* Number of iterations that the write thread attempts to process more pending entries before it
* forces the changes to disk (and releases waiting threads).
* <p/>
* Similar as write delay tries to reduce disk IO by combining individual writes, this value
* attempts to reduce calls to force (fsync) by repeatedly writing any queued requests before
* actually performing a requested force. Once forced any waiting threads are released.
*/
int WRITE_ITERATIONS_BEFORE_FORCE = getInteger("bitronix.nio.journal.writes.before.force", 10);
/**
* Specifies the amount of slots (buffers, lock-free queue entries) to prepare for threads
* trying to log a transaction.
*/
int CONCURRENCY = getInteger("bitronix.nio.journal.concurrency", 1024);
/**
* Specifies the size of byte buffers to allocate for transaction serialization.
* (should be as large as the majority of transactions may become)
*/
int PRE_ALLOCATED_BUFFER_SIZE = getInteger("bitronix.nio.journal.buffer.size", 386);
/**
* Specifies whether direct buffers are used when buffering records before the are written to disk.
*
* Direct buffers are more efficient when writing to disk based on the fact that they can be written
* directly without an additional array copy.
*/
boolean USE_DIRECT_BUFFERS = parseBoolean(getProperty("bitronix.nio.journal.buffer.use.direct", "true"));
/**
* Hard limit, defining the maximum time that a transaction may be held in the journal.
* (= the maximum supported timeout for a transaction, defaults to 14 days)
* <p/>
* This value cleans journal records that are beyond this maximum age and is meant primarily
* to protect the system from leakage that may be caused by crashes, hardware failures or software bugs.
*/
long TRANSACTION_MAX_LIFETIME = max(MS_PER_DAY, getLong("bitronix.nio.journal.max.transaction.lifetime", MS_PER_DAY * 14));
/**
* Defines hard limit for journal record sizes to protect from OOM-Errors through DOS attacks
* or failures with bit-flips inside the stored record size value (defaults to 64k).
* <p/>
* Note: Up to {@link #CONCURRENCY} * 2 * {@code JOURNAL_MAX_RECORD_SIZE} bytes of heap and direct buffer memory (half/half)
* may be required at a time in the worst case scenario.
*/
int JOURNAL_MAX_RECORD_SIZE = max(1024, getInteger("bitronix.nio.journal.max.record.size", 64 * 1024));
/**
* Is the offset of the min required free space in the journal before it is grown after a rollover.
* <p/>
* With the default value of 0.75, a grow happens if 3m are free after a rollover of a 4m file.
* <p/>
* Valid values are within a range of 0.1 <= x <= 0.9.
* <p/>
* If growing isn't possible, the system does not stop working but logs a warning with every failed attempt
* to grow the journal. If growing is required to fit all concurrently opened transactions the system will start
* to throwing IOExceptions when {@code force()} is called.
*/
double JOURNAL_GROW_OFFSET = max(0.1D, min(0.9D, parseDouble(getProperty("bitronix.nio.journal.grow.offset", "0.75"))));
/**
* Is the new size of the journal when it is grown (relative to the journal size).
* <p/>
* With the default value of 1.5, a 4m file is grown by 4m * 1.5 => 6m.
* <p/>
* Settings this value to 1 disables the ability that the journal may grow.
*/
double JOURNAL_GROW_RATIO = max(1D, parseDouble(getProperty("bitronix.nio.journal.grow.ratio", "1.5")));
// ---- SNIPPET-END: NioJournalTuningOptions
/**
* Is a list of short human readable strings that map TX status IDs.
*/
List<String> TRANSACTION_STATUS_STRINGS = unmodifiableList(asList(
"0-ACT:", // Status.STATUS_ACTIVE
"1-MRB:", // Status.STATUS_MARKED_ROLLBACK
"2-PRE:", // Status.STATUS_PREPARED
"3-CTD:", // Status.STATUS_COMMITTED
"4-RBA:", // Status.STATUS_ROLLEDBACK
"5-UKN:", // Status.STATUS_UNKNOWN
"6-NTX:", // Status.STATUS_NO_TRANSACTION
"7-PRI:", // Status.STATUS_PREPARING
"8-COM:", // Status.STATUS_COMMITTING
"9-ROL:", // Status.STATUS_ROLLINGBACK
"<unkn>" // out of bounds
));
/**
* Is a list of human readable strings that map TX status IDs.
*/
List<String> TRANSACTION_LONG_STATUS_STRINGS = unmodifiableList(asList(
"0-ACTIVE", // Status.STATUS_ACTIVE
"1-MARKED_ROLLBACK", // Status.STATUS_MARKED_ROLLBACK
"2-PREPARED", // Status.STATUS_PREPARED
"3-COMMITTED", // Status.STATUS_COMMITTED
"4-ROLLEDBACK", // Status.STATUS_ROLLEDBACK
"5-UNKNOWN", // Status.STATUS_UNKNOWN
"6-NO_TRANSACTION", // Status.STATUS_NO_TRANSACTION
"7-PREPARING", // Status.STATUS_PREPARING
"8-COMMITTING", // Status.STATUS_COMMITTING
"9-ROLLINGBACK", // Status.STATUS_ROLLING_BACK
"<unknown-status>" // out of bounds
));
/**
* Collects the TX states that are used to finalize a transaction.
*/
Set<Integer> FINAL_STATUS = unmodifiableSet(new HashSet<Integer>(asList(
STATUS_COMMITTED,
STATUS_ROLLEDBACK)));
/**
* Collects the TX states that are tracked in memory.
*/
Set<Integer> TRACKED_STATUS = unmodifiableSet(new HashSet<Integer>(asList(
STATUS_ACTIVE,
STATUS_PREPARED,
STATUS_COMMITTED,
STATUS_ROLLEDBACK,
STATUS_PREPARING,
STATUS_COMMITTING,
STATUS_ROLLING_BACK
)));
/**
* Collects the TX states that must be logged in any case.
*/
Set<Integer> MANDATORY_STATUS_TO_LOG = unmodifiableSet(new HashSet<Integer>(asList(
STATUS_UNKNOWN,
STATUS_COMMITTED,
STATUS_ROLLEDBACK,
STATUS_COMMITTING,
STATUS_ROLLING_BACK
)));
}