Promotion - turning a READ into WRITE is work-in-progress. Missing is
the general exposure, testing and controlling modes. (Two versions with
and without read-committed).
The mechanism actually already works for TIM, TDB and TDB2.
If you want to play with the mechanism: enable with global settings:
// TDB
DatasetGraphTransaction.promotion = true;
DatasetGraphTransaction.readCommittedPromotion = false;
// TDB2
TransactionCoordinator.promotion = true;
TransactionCoordinator.readCommittedPromotion = false;
// TIM
DatasetGraphInMemory.promotion = true;
DatasetGraphInMemory.readCommittedPromotion = false;
and "add" etc inside a READ will cause the transaction to turn into a
WRITE (or, with readCommittedPromotion=false may be throw an exception).
Andy
On 27/12/17 16:18, ajs6f wrote:
Then nesting is not safe as you might have open initially a read transaction
and then include a write. If the parent one is a write there
shouldn't be such an issue (I guess).
Actual nesting is not supported right now, period. Transactions in Jena are
currently thread-local, so what you describe above I would see as a mistaken
use of the API. If a client needs to move from a READ to a WRITE transaction,
it's usually appropriate to close the transaction and open a new one
(transactions in TIM, for instance, are snapshot isolated, and I believe the
same is true of TDB2). Transactional objects _should not_ be passed from thread
to thread with open transactions, unless additional client machinery is in
place to manage those transactions, such as Dick has described in another
thread (using thread proxies).
Promotion machinery does exist in Jena but I am not aware that any of the
dataset implementations actually support it right now. I could be wrong about
that, since I didn't write the promotion code. Jena isn't a SQL database and
doesn't offer the same kinds of guarantees or tradeoffs. Correctly promoting
transactions in the absence of information about data dependencies is
non-trivial.
That having been said, it should be possible to add a "transaction type" method to transactional
objects, within the "thread-local" design. Some dataset implementations already have one, e.g.
DatasetGraphInMemory::transactionType. You might want to start by adding it to the
o.a.j.sparql.core.Transactional interface and then "catching up" the implementation code to build
up a PR.
Adam Soroka
On Dec 27, 2017, at 6:53 AM, George News <[email protected]> wrote:
On 2017-12-27 12:29, Claude Warren wrote:
I recently wrote some code to try to handle a similar situation. In my
case I knew I needed a transaction to be active at various points so I
created a TransactionHolder. I create the holder and passing the object
that has implements Transactional as well as the type of ReadWrite I want.
If the transaction is active it does nothing (and I hope the proper
transaction has been started) otherwise It starts the transaction.
Ad the end I call commit or abort as appropriate. If I did not start the
transaction the commit, abort or end is ignored.
I see the same problem in your code as I pointed out before. A
transaction behaves differently if it is READ or WRITE and in your code
there is not such a thing. Actually the isInTransaction() doesn't give
you this information.
Then nesting is not safe as you might have open initially a read
transaction and then include a write. If the parent one is a write there
shouldn't be such an issue (I guess).
Just for you to know, your code is more or less integrated in [1], so
you can "update" your code.
[1]: jena/jena-arq/src/main/java/org/apache/jena/system/Txn.java
I think there may be an issue with abort in that it should probablyset up
end() to throw an exception when I have not created the transaction so
that the outer transaction will fail.
import org.apache.jena.query.ReadWrite;
import org.apache.jena.sparql.core.Transactional;
public class TransactionHolder {
private final Transactional txn;
private final boolean started;
private final ReadWrite rw;
public TransactionHolder( Transactional txn, ReadWrite rw )
{
this.txn = txn;
this.rw = rw;
started = ! txn.isInTransaction();
if (started)
{
txn.begin( rw );
}
}
public boolean ownsTranaction() {
return started;
}
public void commit() {
if (started) {
txn.commit();
}
}
public void abort() {
if (started)
{
txn.abort();
}
}
public void end() {
if (started) {
txn.end();
}
}
}
On Wed, Dec 27, 2017 at 11:03 AM, dandh988 <[email protected]> wrote:
You cannot nest transactions nor can you promote a read to a write.
You need to rewrite your code or use txn which correctly checks if a
transaction is available and if not will begin the correct one, either READ
or WRITE.
Dick
-------- Original message --------From: George News <[email protected]>
Date: 27/12/2017 10:27 (GMT+00:00) To: Jena User Mailing List <
[email protected]> Subject: Txn code not handling type of transaction
Hi,
As you know from other threads I'm having some issues with transactions.
Your suggestion is to use Txn instead of begin/end. Just for curiosity I
have checked the Txn code at [1] and it seems that inside you use
begin/end.
However I have a doubt concerning how you handle the begin/end for READ
and WRITE. It seems that you open a transaction based on
txn.isInTransaction(), but how do you know if it is a READ or WRITE?
If you create something like:
Txn.executeRead(dataset, {
Txn.executeWrite(dataset, {
// Whatever
}
}
}
the txn.begin(ReadWrite.WRITE) is not called and therefore it might be
leading to unexepected behaviours for the txn.commit().
could you give some hints on how this is handle internally? Before fully
modify the code I have, it might be easier to replicate the txn
behaviour ;) but I would like to know the above (if possible).
As always, thanks in advanced
Jorge
[1]: jena/jena-arq/src/main/java/org/apache/jena/system/Txn.java