On 29/12/17 09:51, George News wrote:
On 2017-12-28 18:02, dandh988 wrote:
Can you give a complete example? How are you calling MultiUnion? Are
you calling txn read on the dataset then building the union, then
calling txn write to update the graph?
Let's describe a use case.
The stack trace does not agree with the details here (and details
matter!) especially what dataset is because if that is a general dataset
built out of TDB graphs, this whole thing will not work. A complete,
minimal example is needed.
A few general observations:
1) I have a dataset that includes 4 named graphs: G1, G2, G3, G4
2.a) Someone initiates a sparql request and the internal procedure followed is:
return Txn.calculateRead(dataset, () -> {
// Create multiunion of 3 namegraphs
MultiUnion union = new MultiUnion();
union.addGraph(dataset.getNamedModel("G1").getGraph());
union.addGraph(dataset.getNamedModel("G2").getGraph());
union.addGraph(dataset.getNamedModel("G4").getGraph());
This can be done in SPARQL:
either UNION or
SELECT
FROM <G1>
FROM <G2>
FROM <G4>
WHERE { ... }
(copy the query object and modify it).
and TDB will handle it better.
Model m = ModelFactory.createModelForGraph(union);
You are not querying the TDB dataset if you pass a model to
QueryExecutionFactory.create. It has to create a dataset (a general
purpose one) for the query.
// Launch Sparql query on it
try (QueryExecution qExec = QueryExecutionFactory.create(query, m)) {
return ResultSetFactory.copyResults(qExec.execSelect())
}
});
2.b) Someone initiates a sparql request and the internal procedure followed is:
return Txn.calculateRead(dataset, () -> {
// Create multiunion of 2 namegraphs
// This code in in a function
MultiUnion union = new MultiUnion();
union.addGraph(dataset.getNamedModel("G1").getGraph());
union.addGraph(dataset.getNamedModel("G2").getGraph());
Model m1 = ModelFactory.createModelForGraph(union);
// Retrieve namegraph G3
// This code in in a function
Model m2 = dataset.getNamedModel("G3");
Model m = ModelFactory.createUnion(m2, m1);
// Launch Sparql query on it
try (QueryExecution qExec = QueryExecutionFactory.create(query, m)) {
return ResultSetFactory.copyResults(qExec.execSelect())
}
});
3) Someone initiaties a write in G2
// m stores the new entity model
Model m;
Txn.executeWrite(dataset, () -> {
dataset.getNamedModel("G2").add(m);
});
If either version of 2), and 3) are not done in parallel there is no problem
and everything is executed correctly.
The problem arise when 2.a) or 2.b) is run, and before ending someone tries to perform
3). Then I get the FileException("In the middle of an alloc-write").
Do you have an idea on how to avoid this? How can I handle transactions in this
model?
I was thinking on creating a global mutex so if any action is being performed
over the dataset, then the rest would be blocked. The problem here is that the
code is part of a webservice and then if the read/write operation lasts long, I
will get a timeout that will close the connection.
The other option is to disable writing while someone is reading. The main
problem here is how to properly reschedule writings not to have a big queue.
Any help is more than welcome. I don't know what else to do to solve this is
issue, and the problem is making the service unusable :(
Thanks a lot for the great help you are all offering.
Jorge