Unverified 提交 181cbd36 authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1054 from h2database/txcommit-atomic

Introduce overflow bit in tx state
......@@ -96,6 +96,11 @@ public final class DataUtils {
*/
public static final int ERROR_TRANSACTION_ILLEGAL_STATE = 103;
/**
* The transaction contains too many changes.
*/
public static final int ERROR_TRANSACTION_TOO_BIG = 104;
/**
* The type for leaf page.
*/
......
......@@ -50,7 +50,7 @@ public class Transaction {
* This transaction's id can not be re-used until all the above is completed
* and transaction is closed.
*/
public static final int STATUS_COMMITTED = 4;
private static final int STATUS_COMMITTED = 4;
/**
* The status of a transaction that currently in a process of rolling back
......@@ -68,6 +68,13 @@ public class Transaction {
"CLOSED", "OPEN", "PREPARED", "COMMITTING",
"COMMITTED", "ROLLING_BACK", "ROLLED_BACK"
};
static final int LOG_ID_BITS = 40;
private static final int LOG_ID_BITS1 = LOG_ID_BITS + 1;
private static final long LOG_ID_LIMIT = 1L << LOG_ID_BITS;
private static final long LOG_ID_MASK = (1L << LOG_ID_BITS1) - 1;
private static final int STATUS_BITS = 4;
private static final int STATUS_MASK = (1 << STATUS_BITS) - 1;
/**
* The transaction store.
......@@ -81,8 +88,9 @@ public class Transaction {
/*
* Transation state is an atomic composite field:
* bit 44 : flag whether transaction had rollback(s)
* bits 42-40 : status
* bit 45 : flag whether transaction had rollback(s)
* bits 44-41 : status
* bits 40 : overflow control bit, 1 indicates overflow
* bits 39-0 : log id of the last entry in the undo log map
*/
private final AtomicLong statusAndLogId;
......@@ -202,6 +210,12 @@ public class Transaction {
void log(int mapId, Object key, VersionedValue oldValue) {
long currentState = statusAndLogId.getAndIncrement();
long logId = getLogId(currentState);
if (logId >= LOG_ID_LIMIT) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_TRANSACTION_TOO_BIG,
"Transaction {0} has too many changes",
transactionId);
}
store.log(this, logId, mapId, key, oldValue);
}
......@@ -211,6 +225,12 @@ public class Transaction {
void logUndo() {
long currentState = statusAndLogId.decrementAndGet();
long logId = getLogId(currentState);
if (logId >= LOG_ID_LIMIT) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_TRANSACTION_CORRUPT,
"Transaction {0} has internal error",
transactionId);
}
store.logUndo(this, logId);
}
......@@ -269,7 +289,7 @@ public class Transaction {
* Commit the transaction. Afterwards, this transaction is closed.
*/
public void commit() {
long state = setStatus(Transaction.STATUS_COMMITTING);
long state = setStatus(STATUS_COMMITTING);
long logId = Transaction.getLogId(state);
int oldStatus = Transaction.getStatus(state);
store.commit(this, logId, oldStatus);
......@@ -357,16 +377,16 @@ public class Transaction {
}
public static int getStatus(long state) {
return (int)(state >>> 40) & 15;
private static int getStatus(long state) {
return (int)(state >>> LOG_ID_BITS1) & STATUS_MASK;
}
public static long getLogId(long state) {
return state & ((1L << 40) - 1);
private static long getLogId(long state) {
return state & LOG_ID_MASK;
}
private static boolean hasRollback(long state) {
return (state & (1L << 44)) != 0;
return (state & (1L << (STATUS_BITS + LOG_ID_BITS1))) != 0;
}
private static boolean hasChanges(long state) {
......@@ -374,9 +394,12 @@ public class Transaction {
}
private static long composeState(int status, long logId, boolean hasRollback) {
assert logId < LOG_ID_LIMIT : logId;
assert (status & ~STATUS_MASK) == 0 : status;
if (hasRollback) {
status |= 16;
status |= 1 << STATUS_BITS;
}
return ((long)status << 40) | logId;
return ((long)status << LOG_ID_BITS1) | logId;
}
}
......@@ -156,6 +156,9 @@ public class TransactionStore {
return store.hasMap(name);
}
private static final int LOG_ID_BITS = Transaction.LOG_ID_BITS;
private static final long LOG_ID_MASK = (1L << LOG_ID_BITS) - 1;
/**
* Combine the transaction id and the log id to an operation id.
*
......@@ -164,11 +167,11 @@ public class TransactionStore {
* @return the operation id
*/
static long getOperationId(int transactionId, long logId) {
DataUtils.checkArgument(transactionId >= 0 && transactionId < (1 << 24),
DataUtils.checkArgument(transactionId >= 0 && transactionId < (1 << (64 - LOG_ID_BITS)),
"Transaction id out of range: {0}", transactionId);
DataUtils.checkArgument(logId >= 0 && logId < (1L << 40),
DataUtils.checkArgument(logId >= 0 && logId <= LOG_ID_MASK,
"Transaction log id out of range: {0}", logId);
return ((long) transactionId << 40) | logId;
return ((long) transactionId << LOG_ID_BITS) | logId;
}
/**
......@@ -178,7 +181,7 @@ public class TransactionStore {
* @return the transaction id
*/
static int getTransactionId(long operationId) {
return (int) (operationId >>> 40);
return (int) (operationId >>> LOG_ID_BITS);
}
/**
......@@ -188,7 +191,7 @@ public class TransactionStore {
* @return the log id
*/
static long getLogId(long operationId) {
return operationId & ((1L << 40) - 1);
return operationId & LOG_ID_MASK;
}
/**
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论