-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement transactions based on MarkerDatabase
* Remove all manual interaction with MarkerDatabase. It is used solely to implement writing transactions and waiting for them. * MarkerDatabase provides a JVM internal as well as external locking and waiting mechanism. * Transactions are a per thread ID which may (or may not) cause a MarkerDatabase with that ID to be created whenever required, i.e. when objects are actually inserted in the BHive. * Nested transactions are fully supported. The order in which transactions are closed *must* be the reverse of how they started. * PruneOperation locks the root for all MarkerDatabase's which prevents the creation of new transactions (delays them). Existing transactions are fully respected and can continue to work while this happens. * All transactions can run fully in parallel, PruneOperation is the only place that can cause waiting. * Transactions can be inherited by child Threads and are inherently thread-safe. This is to support multi-threaded file operations. * ObjectDatabase knows about transactions and marks objects it inserts on the active transaction. If there is no transaction, a warning is issued on this level, but no further failure is provoked. * TransactedOperation - a new base class for "writing" operations will in its own check and assure that there is an open transaction, which has to be opened by the caller of such operations, since a single TransactedOperation is very likely to only be a part of a multi-step action (e.g. insert-object, insert-tree, insert-manifest, each separate operations which should be on the same transaction). Request: DCS-1292 Change-Id: Ia852af156717b8996c456dae74ea4989d30765f8
- Loading branch information
Showing
64 changed files
with
750 additions
and
422 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
bhive/src/main/java/io/bdeploy/bhive/BHiveTransactions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package io.bdeploy.bhive; | ||
|
||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.Map; | ||
import java.util.Stack; | ||
import java.util.TreeMap; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import io.bdeploy.bhive.model.ObjectId; | ||
import io.bdeploy.bhive.objects.MarkerDatabase; | ||
import io.bdeploy.bhive.objects.ObjectDatabase; | ||
import io.bdeploy.common.ActivityReporter; | ||
import io.bdeploy.common.util.PathHelper; | ||
import io.bdeploy.common.util.UuidHelper; | ||
|
||
/** | ||
* Keeps track of running operations in the JVM. | ||
* <p> | ||
* Uses MarkerDatabase to synchronize with other JVMs which might have operations running as well. | ||
*/ | ||
public class BHiveTransactions { | ||
|
||
private static final Logger log = LoggerFactory.getLogger(BHiveTransactions.class); | ||
|
||
private final InheritableThreadLocal<Stack<String>> transactions = new InheritableThreadLocal<>(); | ||
private final Map<String, MarkerDatabase> dbs = new TreeMap<>(); | ||
private final ActivityReporter reporter; | ||
private final Path markerRoot; | ||
|
||
public BHiveTransactions(Path markerRoot, ActivityReporter reporter) { | ||
this.markerRoot = markerRoot; | ||
this.reporter = reporter; | ||
} | ||
|
||
private Stack<String> getOrCreate() { | ||
Stack<String> result = transactions.get(); | ||
if (result == null) { | ||
result = new Stack<>(); | ||
transactions.set(result); | ||
} | ||
return result; | ||
} | ||
|
||
/** | ||
* @param object the object which should be considered "touched", i.e. inserted. | ||
*/ | ||
public void touchObject(ObjectId object) { | ||
Stack<String> all = transactions.get(); | ||
String id = (all == null || all.isEmpty()) ? null : all.peek(); | ||
if (id == null) { | ||
throw new IllegalStateException("No transaction active while inserting object."); | ||
} | ||
|
||
MarkerDatabase mdb = dbs.get(id); | ||
if (mdb == null) { | ||
throw new IllegalStateException("Transaction database missing for transaction " + id); | ||
} | ||
|
||
if (!mdb.hasObject(object)) { | ||
mdb.addMarker(object); | ||
} | ||
} | ||
|
||
/** | ||
* @return whether the current thread has an associated transaction. | ||
*/ | ||
public boolean hasTransaction() { | ||
Stack<String> stack = transactions.get(); | ||
return stack != null && !stack.isEmpty(); | ||
} | ||
|
||
/** | ||
* Begins a new transaction on this thread. | ||
* <p> | ||
* Inserts on the {@link ObjectDatabase} of a {@link BHive} will use this transaction to keep track of objects inserted. | ||
* | ||
* @return a {@link Transaction} which will cleanup associated resources when closed. | ||
*/ | ||
public Transaction begin() { | ||
MarkerDatabase.waitRootLock(markerRoot); | ||
|
||
String uuid = UuidHelper.randomId(); | ||
getOrCreate().push(uuid); | ||
dbs.put(uuid, new MarkerDatabase(markerRoot.resolve(uuid), reporter)); | ||
|
||
if (log.isDebugEnabled()) { | ||
log.debug("Starting transaction {}", uuid, new RuntimeException("Starting Transaction")); | ||
} | ||
|
||
return new Transaction() { | ||
|
||
@Override | ||
public void close() { | ||
MarkerDatabase.waitRootLock(markerRoot); | ||
|
||
Stack<String> stack = transactions.get(); | ||
if (stack == null || stack.isEmpty()) { | ||
throw new IllegalStateException("No transaction has been started on this thread!"); | ||
} | ||
|
||
if (!stack.peek().equals(uuid)) { | ||
log.warn("Out-of-order transaction found: {}, expected: {}", stack.peek(), uuid); | ||
} | ||
|
||
if (log.isDebugEnabled()) { | ||
log.debug("Ending transaction {}", uuid, new RuntimeException("Ending Transaction")); | ||
} | ||
|
||
stack.remove(uuid); | ||
dbs.remove(uuid); | ||
|
||
Path mdb = markerRoot.resolve(uuid); | ||
if (!Files.isDirectory(mdb)) { | ||
return; // nothing to clean. | ||
} | ||
|
||
PathHelper.deleteRecursive(mdb); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Represents a writing transaction in the BHive. | ||
*/ | ||
public interface Transaction extends AutoCloseable { | ||
|
||
@Override | ||
public void close(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.