Unverified 提交 143635c9 authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1646 from h2database/javadoc-at

In preparation to a release?
......@@ -1105,10 +1105,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
getVersion(rootReference) > version;
}
public boolean isSingleWriter() {
return singleWriter;
}
/**
* Get the child page count for this page. This is to allow another map
* implementation to override the default, in case the last child is not to
......
......@@ -503,7 +503,7 @@ public class MVStore implements AutoCloseable {
return map;
}
public <M extends MVMap<K, V>, K, V> M openMap(int id, MVMap.MapBuilder<M, K, V> builder) {
private <M extends MVMap<K, V>, K, V> M openMap(int id, MVMap.MapBuilder<M, K, V> builder) {
storeLock.lock();
try {
@SuppressWarnings("unchecked")
......@@ -2963,6 +2963,14 @@ public class MVStore implements AutoCloseable {
return txCounter;
}
/**
* De-register (close) completed operation (transaction).
* This will decrement usage counter for the corresponding version.
* If counter reaches zero, that version (and all unused after it)
* can be dropped immediately.
*
* @param txCounter to be decremented, obtained from registerVersionUsage()
*/
public void deregisterVersionUsage(TxCounter txCounter) {
if(txCounter != null) {
if(txCounter.counter.decrementAndGet() <= 0) {
......@@ -3001,7 +3009,14 @@ public class MVStore implements AutoCloseable {
* which are still operating on this version.
*/
public static final class TxCounter {
/**
* Version of a store, this TxCounter is related to
*/
public final long version;
/**
* Counter of outstanding operation on this version of a store
*/
public final AtomicInteger counter = new AtomicInteger();
TxCounter(long version) {
......
......@@ -518,6 +518,14 @@ public abstract class Page implements Cloneable
return bKeys;
}
/**
* Append additional key/value mappings to this Page.
* New mappings suppose to be in correct key order.
*
* @param extraKeyCount number of mappings to be added
* @param extraKeys to be added
* @param extraValues to be added
*/
abstract void expand(int extraKeyCount, Object[] extraKeys, Object[] extraValues);
/**
......@@ -911,6 +919,12 @@ public abstract class Page implements Cloneable
}
}
/**
* Update given CursorPos chain to correspond to "append point" in a B-tree rooted at this Page.
*
* @param cursorPos to update, presumably pointing to this Page
* @return new head of the CursorPos chain
*/
public abstract CursorPos getAppendCursorPos(CursorPos cursorPos);
/**
......@@ -984,6 +998,11 @@ public abstract class Page implements Cloneable
return page;
}
/**
* Clear if necessary, reference to the actual child Page object,
* so it can be garbage collected if not actively used elsewhere.
* Reference is cleared only if corresponding page was already saved on a disk.
*/
void clearPageReference() {
if (page != null) {
page.writeEnd();
......
......@@ -231,6 +231,11 @@ public class Transaction {
}
}
/**
* Determine if any database changes were made as part of this transaction.
*
* @return true if there are changes to commit, false otherwise
*/
public boolean hasChanges() {
return hasChanges(statusAndLogId.get());
}
......@@ -259,11 +264,17 @@ public class Transaction {
return getLogId();
}
/**
* Mark an entry into a new SQL statement execution within this transaction.
*/
public void markStatementStart() {
markStatementEnd();
txCounter = store.store.registerVersionUsage();
}
/**
* Mark an exit from SQL statement execution within this transaction.
*/
public void markStatementEnd() {
MVStore.TxCounter counter = txCounter;
if(counter != null) {
......@@ -278,6 +289,8 @@ public class Transaction {
* @param mapId the map id
* @param key the key
* @param oldValue the old value
*
* @return key for the newly added undo log entry
*/
long log(int mapId, Object key, VersionedValue oldValue) {
long currentState = statusAndLogId.getAndIncrement();
......@@ -487,6 +500,9 @@ public class Transaction {
}
}
/**
* Transition this transaction into a closed state.
*/
void closeIt() {
long lastState = setStatus(STATUS_CLOSED);
store.store.deregisterVersionUsage(txCounter);
......@@ -499,6 +515,15 @@ public class Transaction {
notifyAll();
}
/**
* Make this transaction to wait for the specified transaction to be closed,
* because both of them try to modify the same map entry.
*
* @param toWaitFor transaction to wait for
* @param map containing blocking entry
* @param key of the blocking entry
* @return true if other transaction was closed and this one can proceed, false if timed out
*/
public boolean waitFor(Transaction toWaitFor, MVMap<?,VersionedValue> map, Object key) {
blockingTransaction = toWaitFor;
blockingMap = map;
......
......@@ -102,6 +102,17 @@ public class TransactionStore {
private static final int MAX_OPEN_TRANSACTIONS = 65535;
/**
* Generate a string used to name undo log map for a specific transaction.
* This name will contain transaction id and reflect the fact
* whether transaction is logically committed or not.
* This information might be used by recovery procedure after unclean shutdown
* (termination before transaction is fully committed).
*
* @param committed true if transaction is logically committed, false otherwise
* @param transactionId of the corresponding transaction
* @return undo log name
*/
public static String getUndoLogName(boolean committed, int transactionId) {
return UNDO_LOG_NAME_PREFIX +
(committed ? UNDO_LOG_COMMITTED : UNDO_LOG_OPEN) +
......
......@@ -9,17 +9,42 @@ import org.h2.mvstore.MVMap;
import org.h2.value.VersionedValue;
/**
* Class TxDecisionMaker.
* Class TxDecisionMaker is a base implementation of MVMap.DecisionMaker
* to be used for TransactionMap modification.
*
* @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/
abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
/**
* Map to decide upon
*/
private final int mapId;
/**
* Key for the map entry to decide upon
*/
private final Object key;
/**
* Value for the map entry
*/
final Object value;
/**
* Transaction we are operating within
*/
private final Transaction transaction;
/**
* Id for the undo log entry created for this modification
*/
long undoKey;
protected long lastOperationId;
/**
* Id of the last operation, we decided to {@link MVMap.Decision.REPEAT}.
*/
private long lastOperationId;
private Transaction blockingTransaction;
private MVMap.Decision decision;
......@@ -56,7 +81,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// transaction is not committed yet
// should wait on blockingTransaction that was determined earlier
decision = MVMap.Decision.ABORT;
} else if (id == lastOperationId) {
} else if (isRepeatedOperation(id)) {
// There is no transaction with that id, and we've tried it just
// before, but map root has not changed (which must be the case if
// we just missed a closed transaction), therefore we came back here
......@@ -72,7 +97,6 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// we can retry immediately and either that entry become committed
// or we'll hit case above
decision = MVMap.Decision.REPEAT;
lastOperationId = id;
}
return decision;
}
......@@ -99,14 +123,33 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
return blockingTransaction;
}
/**
* Create undo log entry
* @param value previous value to be logged
*/
final void logIt(VersionedValue value) {
undoKey = transaction.log(mapId, key, value);
}
/**
* Check whether specified transaction id belongs to "current" transaction
* (transaction we are acting within).
*
* @param transactionId to check
* @return true it it is "current" transaction's id, false otherwise
*/
final boolean isThisTransaction(int transactionId) {
return transactionId == transaction.transactionId;
}
/**
* Determine whether specified id corresponds to a logically committed transaction.
* In case of pending transaction, reference to actual Transaction object (if any)
* is preserved for future use.
*
* @param transactionId to use
* @return true if transaction should be considered as committed, false otherwise
*/
final boolean isCommitted(int transactionId) {
Transaction blockingTx;
boolean result;
......@@ -121,8 +164,30 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
return result;
}
final MVMap.Decision setDecision(MVMap.Decision d) {
return decision = d;
/**
* Store operation id provided, but before that, compare it against last stored one.
* This is to prevent an infinite loop in case of uncommitted "leftover" entry
* (one without a corresponding undo log entry, most likely as a result of unclean shutdown).
*
* @param id for the operation we decided to {@link MVMap.Decision.REPEAT}
* @return true if the same as last operation id, false otherwise
*/
final boolean isRepeatedOperation(long id) {
if (id == lastOperationId) {
return true;
}
lastOperationId = id;
return false;
}
/**
* Record for future references specified value as a decision that has been made.
*
* @param decision made
* @return argument provided
*/
final MVMap.Decision setDecision(MVMap.Decision decision) {
return this.decision = decision;
}
@Override
......@@ -184,7 +249,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// should wait on blockingTransaction that was determined
// earlier and then try again
return setDecision(MVMap.Decision.ABORT);
} else if (id == lastOperationId) {
} else if (isRepeatedOperation(id)) {
// There is no transaction with that id, and we've tried it
// just before, but map root has not changed (which must be
// the case if we just missed a closed transaction),
......@@ -203,7 +268,6 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// transaction has been committed/rolled back and is closed
// by now, so we can retry immediately and either that entry
// become committed or we'll hit case above
lastOperationId = id;
return setDecision(MVMap.Decision.REPEAT);
}
}
......
......@@ -157,7 +157,7 @@ dateadd datediff datepart dates datestyle datetime datetimes datum david davide
day daylight dayname dayofmonth dayofweek dayofyear days dba dbbench dbcp dbid
dbms dbname dbo dbs dbserv dbsnmp dclassifier dcmpg dcmpl dconst ddiv ddl
ddladmin deactivate deactivated deactivation dead deadlock deadlocked deadlocks
deal dealing deallocate death debug debugging dec decade december decide decimal
deal dealing deallocate death debug debugging dec decade december decide decided decimal
decision deck declaration declarations declarative declaratory declare declared
declaring decode decoded decoder decodes decoding decompile decompiler decompiles
decompiling decompress decompressed decompresser decompression decoration
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论