com.bigdata.rdf.sail.CreateKBTask Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Apr 13, 2011
*/
package com.bigdata.rdf.sail;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.log4j.Logger;
import com.bigdata.ha.HAGlue;
import com.bigdata.ha.QuorumService;
import com.bigdata.journal.IIndexManager;
import com.bigdata.journal.IJournal;
import com.bigdata.journal.ITransactionService;
import com.bigdata.journal.ITx;
import com.bigdata.journal.Journal;
import com.bigdata.quorum.AsynchronousQuorumCloseException;
import com.bigdata.quorum.Quorum;
import com.bigdata.rdf.store.AbstractTripleStore;
import com.bigdata.rdf.store.LocalTripleStore;
import com.bigdata.rdf.store.ScaleOutTripleStore;
import com.bigdata.rdf.task.AbstractApiTask;
import com.bigdata.util.InnerCause;
/**
* Task creates a KB for the given namespace iff no such KB exists. The correct
* use of this class is as follows:
*
*
* AbstractApiTask.submitApiTask(indexManager, new CreateKBTask(namespace, properties)).get();
*
*
* @see DestroyKBTask
* @author Bryan Thompson
*/
public class CreateKBTask extends AbstractApiTask {
private static final transient Logger log = Logger
.getLogger(CreateKBTask.class);
// private final IIndexManager indexManager;
/**
* The effective properties that will be used to create the namespace.
*/
private final Properties properties;
/**
* Return the effective properties that will be used to create the namespace.
*/
protected Properties getProperties() {
return properties;
}
public CreateKBTask(final String namespace, final Properties properties) {
super(namespace, ITx.UNISOLATED, true/* isGRSRequired */);
if (properties == null)
throw new IllegalArgumentException();
// Use the caller's properties as the default.
this.properties = new Properties(properties);
// override the namespace.
this.properties.setProperty(BigdataSail.Options.NAMESPACE, namespace);
}
@Override
final public boolean isReadOnly() {
return false;
}
@Override
public Void call() throws Exception {
try {
doRun();
} catch (Throwable t) {
if (InnerCause.isInnerCause(t, AsynchronousQuorumCloseException.class)) {
/*
* The quorum is closed, so we stopped trying.
*
* Note: This can also happen if the quorum has not been started
* yet. The HAJournalServer explicitly invokes the CreateKBTask
* when entering "RunMet" in order to handle this case.
*/
log.warn(t);
} else {
log.error(t, t);
}
throw new Exception(t);
}
return null;
}
/**
* Note: This process is not robust if the leader is elected and becomes
* HAReady and then fails over before the KB is created. The task should be
* re-submitted by the new leader once that leader is elected.
*/
private void doRun() {
final IIndexManager indexManager = getIndexManager();
if (indexManager instanceof IJournal) {
/*
* Create a local triple store.
*
* Note: This hands over the logic to some custom code located
* on the BigdataSail.
*/
final IJournal jnl = (IJournal) indexManager;
final Quorum> quorum = jnl
.getQuorum();
boolean isSoloOrLeader;
if (quorum == null) {
isSoloOrLeader = true;
} else {
/*
* Wait for a quorum meet.
*/
final long token;
try {
long tmp = quorum.token();
if (tmp == Quorum.NO_QUORUM) {
// Only log if we are going to wait.
log.warn("Awaiting quorum.");
tmp = quorum.awaitQuorum();
}
token = tmp;
assert token != Quorum.NO_QUORUM;
} catch (AsynchronousQuorumCloseException e1) {
throw new RuntimeException(e1);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
/*
* Now wait until the service is HAReady.
*/
try {
jnl.awaitHAReady(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (AsynchronousQuorumCloseException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
throw new RuntimeException(e);
}
if (quorum.getMember().isLeader(token)) {
isSoloOrLeader = true;
} else {
isSoloOrLeader = false;
}
final IJournal journal = jnl;
if (journal.isGroupCommit()
&& journal.getRootBlockView().getCommitCounter() == 0L) {
/*
* Force the GRS to be materialized. This is necessary for the
* initial KB create when using group commit and HA. (For HA the
* initial KB create is single threaded within the context of the
* leader election. However, this is not true for a standalone
* Journal.)
*
* Note: This logic will fail if AbstractTask uses a
* DefaultResourceLocator that is based on the HAJournal and not
* on an IsolatedActionJournal because that will allow the
* GlobalRowStoreHelper.getGlobalRowStore() method to registerr
* the GSR index on the unisolated Name2Addr rather than the n2a
* class inside of the AbstractTask.
*/
journal.getGlobalRowStore();
journal.commit();
}
}
if (isSoloOrLeader) {
// Attempt to resolve the namespace.
if (indexManager.getResourceLocator().locate(namespace,
ITx.UNISOLATED) == null) {
if(log.isInfoEnabled())
log.info("Creating KB instance: namespace=" + namespace);
// create the appropriate as configured triple/quad store.
createLTS(jnl, getProperties());
if(log.isInfoEnabled())
log.info("Created tripleStore: " + namespace);
} // if( tripleStore == null )
}
} else {
// Attempt to resolve the namespace.
if (indexManager.getResourceLocator()
.locate(namespace, ITx.UNISOLATED) == null) {
/*
* Register triple store for scale-out.
*/
if (log.isInfoEnabled())
log.info("Creating KB instance: namespace=" + namespace);
final ScaleOutTripleStore lts = new ScaleOutTripleStore(
indexManager, namespace, ITx.UNISOLATED, getProperties());
lts.create();
if (log.isInfoEnabled())
log.info("Created tripleStore: " + namespace);
} // if( tripleStore == null )
}
}
/**
* Create an {@link AbstractTripleStore} instance against a local database.
*
* Note: For group commit, the caller will be holding the resource lock for
* the namespace.
*
* @param indexManager
* @param properties
* @return
*/
private AbstractTripleStore createLTS(final IJournal indexManager, final Properties properties) {
final ITransactionService txService = indexManager
.getLocalTransactionManager().getTransactionService();
final String namespace = properties.getProperty(
BigdataSail.Options.NAMESPACE,
BigdataSail.Options.DEFAULT_NAMESPACE);
// throws an exception if there are inconsistent properties
BigdataSail.checkProperties(properties);
/**
* Note: Unless group commit is enabled, we need to make this operation
* mutually exclusive with KB level writers in order to avoid the
* possibility of a triggering a commit during the middle of a
* BigdataSailConnection level operation (or visa versa).
*
* Note: When group commit is not enabled, the indexManager will be a
* Journal class. When it is enabled, it will merely implement the
* IJournal interface.
*
* @see #1143 (Isolation broken in NSS when groupCommit disabled)
*/
final boolean isGroupCommit = indexManager.isGroupCommit();
boolean acquiredConnection = false;
try {
if (!isGroupCommit) {
try {
// acquire the unisolated connection permit.
((Journal) indexManager).acquireUnisolatedConnection();
acquiredConnection = true;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// Check for pre-existing instance.
{
final LocalTripleStore lts = (LocalTripleStore) indexManager
.getResourceLocator().locate(namespace, ITx.UNISOLATED);
if (lts != null) {
return lts;
}
}
// Create a new instance.
{
if (Boolean.parseBoolean(properties.getProperty(
BigdataSail.Options.ISOLATABLE_INDICES,
BigdataSail.Options.DEFAULT_ISOLATABLE_INDICES))) {
/*
* Isolatable indices: requires the use of a tx to create the KB
* instance.
*/
final long txCreate = txService.newTx(ITx.UNISOLATED);
boolean ok = false;
try {
final AbstractTripleStore txCreateView = new LocalTripleStore(
indexManager, namespace, Long.valueOf(txCreate),
properties);
// create the kb instance within the tx.
txCreateView.create();
// commit the tx.
txService.commit(txCreate);
ok = true;
} finally {
if (!ok)
txService.abort(txCreate);
}
} else {
/*
* Create KB without isolatable indices.
*/
final LocalTripleStore lts = new LocalTripleStore(indexManager,
namespace, ITx.UNISOLATED, properties);
lts.create();
}
}
/*
* Now that we have created the instance, either using a tx or the
* unisolated connection, locate the triple store resource and return
* it.
*/
{
final LocalTripleStore lts = (LocalTripleStore) indexManager
.getResourceLocator().locate(namespace, ITx.UNISOLATED);
if (lts == null) {
/*
* This should only occur if there is a concurrent destroy, which
* is highly unlikely to say the least.
*/
throw new RuntimeException("Concurrent create/destroy: "
+ namespace);
}
return lts;
}
} catch (IOException ex) {
throw new RuntimeException(ex);
} finally {
if (!isGroupCommit && acquiredConnection) {
/**
* When group commit is not enabled, we need to release the
* unisolated connection.
*
* @see #1143 (Isolation broken in NSS when groupCommit disabled)
*/
((Journal) indexManager).releaseUnisolatedConnection();
}
}
}
}