You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2014/06/13 10:57:37 UTC
[017/100] [abbrv] [partial] Reverting the erroneous merge by
Sebastian according to the instructions in INFRA-6876
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiPersistence.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiPersistence.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiPersistence.java
index 27927f3..98ff1b9 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiPersistence.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiPersistence.java
@@ -17,11 +17,14 @@
*/
package org.apache.marmotta.kiwi.persistence;
+import com.google.common.util.concurrent.AtomicLongMap;
import org.apache.marmotta.kiwi.caching.KiWiCacheManager;
+import org.apache.marmotta.kiwi.config.KiWiConfiguration;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
import org.apache.marmotta.kiwi.persistence.util.ScriptRunner;
+import org.apache.marmotta.kiwi.sail.KiWiValueFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.openrdf.model.Statement;
@@ -33,10 +36,15 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
-import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
-import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Add file description here!
@@ -51,34 +59,65 @@ public class KiWiPersistence {
private static int KIWI_ID = 0;
/**
- * A unique name for identifying this instance of KiWiPersistence. Can be used in case there are several
- * instances running in the same environment.
+ * The connection pool for managing JDBC connections
*/
- private String name;
+ private DataSource connectionPool;
+
+ private PoolProperties poolConfig;
+ private KiWiCacheManager cacheManager;
+
+ private KiWiGarbageCollector garbageCollector;
/**
- * The connection pool for managing JDBC connections
+ * The KiWi configuration for this persistence.
*/
- private DataSource connectionPool;
+ private KiWiConfiguration configuration;
/**
- * The SQL dialect to use
+ * A map holding in-memory sequences to be used for sequence caching in case the appropriate configuration option
+ * is configued and batched commits are enabled.
*/
- private KiWiDialect dialect;
+ private AtomicLongMap<String> memorySequences;
- private PoolProperties poolConfig;
+ private ReentrantLock sequencesLock;
- private KiWiCacheManager cacheManager;
- private KiWiGarbageCollector garbageCollector;
+ /**
+ * A reference to the value factory used to access this store. Used for notifications when to flush batches.
+ */
+ private KiWiValueFactory valueFactory;
+
+ /**
+ * This lock allows setting the backend into maintenance mode (by locking the write lock), which essentially
+ * grants an exclusive access to the database. This is currently used by the garbage collector, but can also
+ * be used in other situations-
+ */
+ private boolean maintenance;
+
+ private boolean droppedDatabase = false;
+
+ private boolean initialized = false;
+
+ // keep track which memory sequences have been updated and need to be written back
+ private Set<String> sequencesUpdated;
+
+ @Deprecated
public KiWiPersistence(String name, String jdbcUrl, String db_user, String db_password, KiWiDialect dialect) {
- this.name = name;
- this.dialect = dialect;
+ this(new KiWiConfiguration(name,jdbcUrl,db_user,db_password,dialect));
+ }
+
+ public KiWiPersistence(KiWiConfiguration configuration) {
+ this.configuration = configuration;
+ this.maintenance = false;
+ this.sequencesLock = new ReentrantLock();
+ this.sequencesUpdated = new HashSet<>();
+ }
+ public void initialise() {
// init JDBC connection pool
- initConnectionPool(jdbcUrl, db_user, db_password);
+ initConnectionPool();
// init EHCache caches
initCachePool();
@@ -92,10 +131,14 @@ public class KiWiPersistence {
}
+ //garbageCollector.start();
+
+ initialized = true;
}
+
public KiWiDialect getDialect() {
- return dialect;
+ return configuration.getDialect();
}
public KiWiCacheManager getCacheManager() {
@@ -104,30 +147,39 @@ public class KiWiPersistence {
private void initCachePool() {
- cacheManager = new KiWiCacheManager(name);
+ cacheManager = new KiWiCacheManager(configuration.getName());
}
- private void initConnectionPool(String jdbcUrl, String db_user, String db_password) {
+ private void initConnectionPool() {
poolConfig = new PoolProperties();
poolConfig.setName("kiwi-" + (++KIWI_ID));
- poolConfig.setUrl(jdbcUrl);
- poolConfig.setDriverClassName(dialect.getDriverClass());
- poolConfig.setUsername(db_user);
- poolConfig.setPassword(db_password);
+ poolConfig.setUrl(configuration.getJdbcUrl());
+ poolConfig.setDriverClassName(configuration.getDialect().getDriverClass());
+ poolConfig.setUsername(configuration.getDbUser());
+ poolConfig.setPassword(configuration.getDbPassword());
poolConfig.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
poolConfig.setCommitOnReturn(true);
+ poolConfig.setValidationQuery(configuration.getDialect().getValidationQuery());
+ poolConfig.setLogValidationErrors(true);
/*
poolConfig.setLogAbandoned(true);
poolConfig.setRemoveAbandoned(true);
*/
// interceptors
- poolConfig.setJdbcInterceptors(
- "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;" +
- "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;" +
- "org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport"
- );
+ if(configuration.isQueryLoggingEnabled()) {
+ poolConfig.setJdbcInterceptors(
+ "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;" +
+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;" +
+ "org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport"
+ );
+ } else {
+ poolConfig.setJdbcInterceptors(
+ "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;" +
+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
+ );
+ }
if(log.isDebugEnabled()) {
poolConfig.setSuspectTimeout(30);
@@ -151,9 +203,63 @@ public class KiWiPersistence {
}
+ /**
+ * Initialise in-memory sequences if the feature is enabled.
+ */
+ public void initSequences(String scriptName) {
+ if(configuration.isBatchCommit() && configuration.isMemorySequences()) {
+ sequencesLock.lock();
+ try {
+ if(memorySequences == null) {
+ memorySequences = AtomicLongMap.create();
+ }
+
+ try {
+ Connection con = getJDBCConnection(true);
+ try {
+ for(String sequenceName : getDialect().listSequences(scriptName)) {
+
+ // load sequence value from database
+ // if there is a preparation needed to update the transaction, run it first
+ if(getDialect().hasStatement(sequenceName+".prep")) {
+ PreparedStatement prepNodeId = con.prepareStatement(getDialect().getStatement(sequenceName+".prep"));
+ prepNodeId.executeUpdate();
+ prepNodeId.close();
+ }
+
+ PreparedStatement queryNodeId = con.prepareStatement(getDialect().getStatement(sequenceName));
+ ResultSet resultNodeId = queryNodeId.executeQuery();
+ try {
+ if(resultNodeId.next()) {
+ memorySequences.put(sequenceName,resultNodeId.getLong(1)-1);
+ } else {
+ throw new SQLException("the sequence did not return a new value");
+ }
+ } finally {
+ resultNodeId.close();
+ }
+
+ con.commit();
+ }
+ } finally {
+ releaseJDBCConnection(con);
+ }
+ } catch(SQLException ex) {
+ log.warn("database error: could not initialise in-memory sequences",ex);
+ }
+ } finally {
+ sequencesLock.unlock();
+ }
+ }
+ }
+
public void logPoolInfo() throws SQLException {
- log.debug("num_busy_connections: {}", connectionPool.getNumActive());
- log.debug("num_idle_connections: {}", connectionPool.getNumIdle());
+ if(connectionPool != null) {
+ log.debug("num_busy_connections: {}", connectionPool.getNumActive());
+ log.debug("num_idle_connections: {}", connectionPool.getNumIdle());
+ } else {
+ log.debug("connection pool not initialized");
+ }
}
@@ -190,14 +296,14 @@ public class KiWiPersistence {
log.info("creating new KiWi database ...");
ScriptRunner runner = new ScriptRunner(connection.getJDBCConnection(), false, false);
- runner.runScript(new StringReader(dialect.getCreateScript(scriptName)));
+ runner.runScript(new StringReader(configuration.getDialect().getCreateScript(scriptName)));
} else {
int version = connection.getDatabaseVersion();
- String updateScript = dialect.getMigrationScript(version,scriptName);
+ String updateScript = configuration.getDialect().getMigrationScript(version,scriptName);
if(updateScript != null && updateScript.length() > 0) {
- log.info("upgrading existing KiWi database from version {} to version {}", version, dialect.getVersion());
+ log.info("upgrading existing KiWi database from version {} to version {}", version, configuration.getDialect().getVersion());
ScriptRunner runner = new ScriptRunner(connection.getJDBCConnection(), false, false);
runner.runScript(new StringReader(updateScript));
@@ -206,7 +312,7 @@ public class KiWiPersistence {
log.info("connecting to existing KiWi database (version: {})",version);
}
}
- connection.commit();
+ connection.getJDBCConnection().commit();
} catch (SQLException ex) {
log.error("SQL exception while initialising database, rolling back");
connection.rollback();
@@ -217,6 +323,9 @@ public class KiWiPersistence {
} finally {
connection.close();
}
+
+ // init the in-memory sequences
+ initSequences(scriptName);
}
/**
@@ -258,7 +367,7 @@ public class KiWiPersistence {
}
ScriptRunner runner = new ScriptRunner(connection.getJDBCConnection(), false, false);
- runner.runScript(new StringReader(dialect.getDropScript(scriptName)));
+ runner.runScript(new StringReader(configuration.getDialect().getDropScript(scriptName)));
if(log.isDebugEnabled()) {
@@ -268,7 +377,7 @@ public class KiWiPersistence {
log.debug("- found table: {}",table);
}
}
- connection.commit();
+ connection.getJDBCConnection().commit();
} catch (SQLException ex) {
log.error("SQL exception while dropping database, rolling back");
connection.rollback();
@@ -282,6 +391,8 @@ public class KiWiPersistence {
} catch(SQLException ex) {
log.error("SQL exception while acquiring database connection");
}
+
+ droppedDatabase = true;
}
/**
@@ -291,7 +402,20 @@ public class KiWiPersistence {
* @throws SQLException in case a new connection could not be established
*/
public KiWiConnection getConnection() throws SQLException {
- return new KiWiConnection(this,dialect,cacheManager);
+ if(!initialized) {
+ throw new SQLException("persistence backend not initialized; call initialise before acquiring a connection");
+ }
+
+ if(connectionPool != null) {
+ KiWiConnection con = new KiWiConnection(this,configuration.getDialect(),cacheManager);
+ if(getDialect().isBatchSupported()) {
+ con.setBatchCommit(configuration.isBatchCommit());
+ con.setBatchSize(configuration.getBatchSize());
+ }
+ return con;
+ } else {
+ throw new SQLException("connection pool is closed, database connections not available");
+ }
}
/**
@@ -300,18 +424,60 @@ public class KiWiPersistence {
* @throws SQLException
*/
public Connection getJDBCConnection() throws SQLException {
- Connection conn = connectionPool.getConnection();
- conn.setAutoCommit(false);
- //conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+ return getJDBCConnection(false);
+ }
- //managedConnections.add(conn);
+ /**
+ * Return a raw JDBC connection from the connection pool, which already has the auto-commit disabled.
+ * @return
+ * @throws SQLException
+ */
+ public Connection getJDBCConnection(boolean maintenance) throws SQLException {
+ synchronized (this) {
+ if(this.maintenance) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { }
+ }
+ if(maintenance) {
+ this.maintenance = true;
+ }
+ }
+
+ if(initialized && connectionPool != null) {
+ Connection conn = connectionPool.getConnection();
+ conn.setAutoCommit(false);
- return conn;
+ return conn;
+ } else {
+ throw new SQLException("connection pool is closed, database connections not available");
+ }
}
+ /**
+ * Release the JDBC connection passed as argument. This method will close the connection and release
+ * any locks that might be held by the caller.
+ * @param con
+ * @throws SQLException
+ */
+ public void releaseJDBCConnection(Connection con) throws SQLException {
+ try {
+ con.close();
+ } finally {
+ synchronized (this) {
+ if(this.maintenance) {
+ this.maintenance = false;
+ this.notifyAll();
+ }
+ }
+ }
+ }
+
private void forceCloseConnections() {
- connectionPool.close(true);
+ if(connectionPool != null) {
+ connectionPool.close(true);
+ }
connectionPool = new DataSource(poolConfig);
}
@@ -340,63 +506,33 @@ public class KiWiPersistence {
garbageCollector.addTripleTableDependency(tableName, columnName);
}
- /**
- * Return a Sesame RepositoryResult of statements according to the query pattern given in the arguments. Each of
- * the parameters subject, predicate, object and context may be null, indicating a wildcard query. If the boolean
- * parameter "inferred" is set to true, the result will also include inferred triples, if it is set to false only
- * base triples.
- * <p/>
- * The RepositoryResult holds a direct connection to the database and needs to be closed properly, or otherwise
- * the system might run out of resources. The returned RepositoryResult will try its best to clean up when the
- * iteration has completed or the garbage collector calls the finalize() method, but this can take longer than
- * necessary.
- * <p/>
- * This method will create a new database connection for running the query which is only released when the
- * result is closed.
- *
- *
- * @param subject the subject to query for, or null for a wildcard query
- * @param predicate the predicate to query for, or null for a wildcard query
- * @param object the object to query for, or null for a wildcard query
- * @param context the context to query for, or null for a wildcard query
- * @param inferred if true, the result will also contain triples inferred by the reasoner, if false not
- * @return a new RepositoryResult with a direct connection to the database; the result should be properly closed
- * by the caller
- */
- public RepositoryResult<Statement> listTriples(KiWiResource subject, KiWiUriResource predicate, KiWiNode object, KiWiResource context, boolean inferred) throws SQLException {
- final KiWiConnection conn = getConnection();
- return new RepositoryResult<Statement>(conn.listTriples(subject,predicate,object,context,inferred)) {
- @Override
- protected void handleClose() throws RepositoryException {
- super.handleClose();
+ public void shutdown() {
+ initialized = false;
+
+ if(!droppedDatabase && !configuration.isCommitSequencesOnCommit()) {
+ log.info("storing in-memory sequences in database ...");
+ try {
+ KiWiConnection connection = getConnection();
try {
- if(!conn.isClosed()) {
- conn.commit();
- conn.close();
- }
- } catch (SQLException ex) {
- throw new RepositoryException("SQL error when closing database connection",ex);
+ connection.commitMemorySequences();
+ connection.commit();
+ } finally {
+ connection.close();
}
+ } catch (SQLException e) {
+ log.error("could not store back values of in-memory sequences", e);
}
+ }
- @Override
- protected void finalize() throws Throwable {
- handleClose();
- super.finalize();
- }
- };
- }
-
-
- public void initialise() {
- garbageCollector.start();
- }
- public void shutdown() {
garbageCollector.shutdown();
cacheManager.shutdown();
connectionPool.close();
+
+ connectionPool = null;
+ memorySequences = null;
+
}
/**
@@ -407,4 +543,46 @@ public class KiWiPersistence {
}
+ public void setValueFactory(KiWiValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ public KiWiValueFactory getValueFactory() {
+ return valueFactory;
+ }
+
+ public KiWiConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ public AtomicLongMap<String> getMemorySequences() {
+ return memorySequences;
+ }
+
+ public long incrementAndGetMemorySequence(String name) {
+ sequencesUpdated.add(name);
+
+ if(memorySequences != null) {
+ return memorySequences.incrementAndGet(name);
+ } else {
+ return 0;
+ }
+ }
+
+
+ public void garbageCollect() throws SQLException {
+ this.garbageCollector.garbageCollect();
+ }
+
+ public boolean checkConsistency() throws SQLException {
+ return garbageCollector.checkConsistency();
+ }
+
+ public Set<String> getSequencesUpdated() {
+ return sequencesUpdated;
+ }
+
+ public void setSequencesUpdated(Set<String> sequencesUpdated) {
+ this.sequencesUpdated = sequencesUpdated;
+ }
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java
index dc57948..8bbb1a6 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java
@@ -44,4 +44,47 @@ public class H2Dialect extends KiWiDialect {
public String getDriverClass() {
return "org.h2.Driver";
}
+
+ @Override
+ public boolean isBatchSupported() {
+ return false;
+ }
+
+ @Override
+ public String getRegexp(String text, String pattern) {
+ return text + " REGEXP " + pattern;
+ }
+
+ @Override
+ public String getILike(String text, String pattern) {
+ return "lower("+text+") LIKE lower("+pattern+")";
+ }
+
+
+
+ @Override
+ public String getConcat(String... args) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("CONCAT(");
+ for(int i=0; i<args.length; i++) {
+ buf.append(args[i]);
+ if(i + 1 <args.length) {
+ buf.append(",");
+ }
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ /**
+ * Get the query string that can be used for validating that a JDBC connection to this database is still valid.
+ * Typically, this should be an inexpensive operation like "SELECT 1",
+ *
+ * @return
+ */
+ @Override
+ public String getValidationQuery() {
+ return "SELECT 1";
+ }
+
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java
index 73722de..7914363 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java
@@ -55,4 +55,47 @@ public class MySQLDialect extends KiWiDialect {
public String getDriverClass() {
return "com.mysql.jdbc.Driver";
}
+
+ @Override
+ public boolean isBatchSupported() {
+ return true;
+ }
+
+ @Override
+ public String getRegexp(String text, String pattern) {
+ return text + " RLIKE " + pattern;
+ }
+
+ @Override
+ public String getILike(String text, String pattern) {
+ return "lower("+text+") LIKE lower("+pattern+")";
+ }
+
+
+ @Override
+ public String getConcat(String... args) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("CONCAT(");
+ for(int i=0; i<args.length; i++) {
+ buf.append(args[i]);
+ if(i + 1 <args.length) {
+ buf.append(",");
+ }
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+
+ /**
+ * Get the query string that can be used for validating that a JDBC connection to this database is still valid.
+ * Typically, this should be an inexpensive operation like "SELECT 1",
+ *
+ * @return
+ */
+ @Override
+ public String getValidationQuery() {
+ return "SELECT 1";
+ }
+
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java
index c517d0f..4110309 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java
@@ -45,4 +45,56 @@ public class PostgreSQLDialect extends KiWiDialect {
public String getDriverClass() {
return "org.postgresql.Driver";
}
+
+ @Override
+ public boolean isBatchSupported() {
+ return true;
+ }
+
+ @Override
+ public String getRegexp(String text, String pattern) {
+ return text + " ~ " + pattern;
+ }
+
+ @Override
+ public String getILike(String text, String pattern) {
+ return text + " ILIKE " + pattern;
+ }
+
+
+
+ @Override
+ public String getConcat(String... args) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("(");
+ for(int i=0; i<args.length; i++) {
+ buf.append(args[i]);
+ if(i + 1 <args.length) {
+ buf.append("||");
+ }
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ /**
+ * Get the query string that can be used for validating that a JDBC connection to this database is still valid.
+ * Typically, this should be an inexpensive operation like "SELECT 1",
+ *
+ * @return
+ */
+ @Override
+ public String getValidationQuery() {
+ return "SELECT 1";
+ }
+
+ /**
+ * Return true in case the database system supports using cursors for queries over large data tables.
+ *
+ * @return
+ */
+ @Override
+ public boolean isCursorSupported() {
+ return true;
+ }
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiSailConnection.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiSailConnection.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiSailConnection.java
index d4c84b3..a46bee1 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiSailConnection.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiSailConnection.java
@@ -20,24 +20,15 @@ package org.apache.marmotta.kiwi.sail;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-import info.aduna.iteration.CloseableIteration;
-import info.aduna.iteration.DelayedIteration;
-import info.aduna.iteration.ExceptionConvertingIteration;
-import info.aduna.iteration.Iteration;
-import info.aduna.iteration.Iterations;
-import info.aduna.iteration.UnionIteration;
+import info.aduna.iteration.*;
+import org.apache.marmotta.commons.sesame.repository.ResourceConnection;
import org.apache.marmotta.kiwi.model.rdf.KiWiNamespace;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
import org.apache.marmotta.kiwi.persistence.KiWiConnection;
-import org.openrdf.model.Namespace;
-import org.openrdf.model.Resource;
-import org.openrdf.model.Statement;
-import org.openrdf.model.URI;
-import org.openrdf.model.Value;
-import org.openrdf.model.ValueFactory;
+import org.openrdf.model.*;
import org.openrdf.query.BindingSet;
import org.openrdf.query.Dataset;
import org.openrdf.query.QueryEvaluationException;
@@ -49,7 +40,9 @@ import org.openrdf.query.algebra.Var;
import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
import org.openrdf.query.algebra.evaluation.TripleSource;
import org.openrdf.query.algebra.evaluation.impl.*;
+import org.openrdf.query.impl.EmptyBindingSet;
import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
import org.openrdf.sail.Sail;
import org.openrdf.sail.SailChangedEvent;
import org.openrdf.sail.SailException;
@@ -70,7 +63,7 @@ import java.util.Set;
* <p/>
* Author: Sebastian Schaffert
*/
-public class KiWiSailConnection extends NotifyingSailConnectionBase implements InferencerConnection {
+public class KiWiSailConnection extends NotifyingSailConnectionBase implements InferencerConnection, ResourceConnection {
private static final Logger log = LoggerFactory.getLogger(KiWiSailConnection.class);
@@ -89,7 +82,6 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
private boolean triplesAdded, triplesRemoved;
- private HashSet<Long> deletedStatementsLog;
public KiWiSailConnection(KiWiStore sailBase) throws SailException {
super(sailBase);
@@ -149,7 +141,14 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
}
}
if(contextSet.size() == 0) {
- contextSet.add(valueFactory.createURI(defaultContext));
+ if(defaultContext != null) {
+ contextSet.add(valueFactory.createURI(defaultContext));
+ } else {
+ contextSet.add(null);
+ }
+ }
+ if(inferred && inferredContext != null) {
+ contextSet.add(valueFactory.createURI(inferredContext));
}
KiWiResource ksubj = valueFactory.convert(subj);
@@ -164,16 +163,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
KiWiTriple triple = (KiWiTriple)valueFactory.createStatement(ksubj,kpred,kobj,kcontext, databaseConnection);
triple.setInferred(inferred);
- if(triple.getId() == null) {
- databaseConnection.storeTriple(triple);
- triplesAdded = true;
- notifyStatementAdded(triple);
- } else if(deletedStatementsLog.contains(triple.getId())) {
- // this is a hack for a concurrency problem that may occur in case the triple is removed in the
- // transaction and then added again; in these cases the createStatement method might return
- // an expired state of the triple because it uses its own database connection
-
- databaseConnection.undeleteTriple(triple);
+ if(databaseConnection.storeTriple(triple)) {
triplesAdded = true;
notifyStatementAdded(triple);
}
@@ -238,7 +228,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
new FilterOptimizer().optimize(tupleExpr, dataset, bindings);
new OrderLimitOptimizer().optimize(tupleExpr, dataset, bindings);
- return strategy.evaluate(tupleExpr, bindings);
+ return strategy.evaluate(tupleExpr, EmptyBindingSet.getInstance());
} catch (QueryEvaluationException e) {
throw new SailException(e);
@@ -249,11 +239,16 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
@Override
protected CloseableIteration<? extends Resource, SailException> getContextIDsInternal() throws SailException {
try {
- return new ExceptionConvertingIteration<Resource, SailException>(databaseConnection.listContexts()) {
+ return new FilterIteration<Resource, SailException>(new ExceptionConvertingIteration<Resource, SailException>(databaseConnection.listContexts()) {
@Override
protected SailException convert(Exception e) {
return new SailException("database error while iterating over result set",e);
}
+ }) {
+ @Override
+ protected boolean accept(Resource object) throws SailException {
+ return !object.stringValue().equals(defaultContext);
+ }
};
} catch (SQLException e) {
throw new SailException("database error while listing contexts",e);
@@ -270,7 +265,16 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
contextSet.addAll(Lists.transform(Arrays.asList(contexts), new Function<Resource, KiWiResource>() {
@Override
public KiWiResource apply(Resource input) {
- return valueFactory.convert(input);
+ if(input == null) {
+ if(defaultContext != null) {
+ // null value for context means statements without context; in KiWi, this means "default context"
+ return (KiWiUriResource)valueFactory.createURI(defaultContext);
+ } else {
+ return null;
+ }
+ } else {
+ return valueFactory.convert(input);
+ }
}
}));
@@ -281,7 +285,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
@Override
protected Iteration<? extends Statement, ? extends RepositoryException> createIteration() throws RepositoryException {
try {
- return databaseConnection.listTriples(rsubj, rpred, robj, context, includeInferred);
+ return databaseConnection.listTriples(rsubj, rpred, robj, context, includeInferred, false);
} catch (SQLException e) {
throw new RepositoryException("database error while listing triples",e);
}
@@ -293,7 +297,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
@Override
protected Iteration<? extends Statement, ? extends RepositoryException> createIteration() throws RepositoryException {
try {
- return databaseConnection.listTriples(rsubj, rpred, robj, null, includeInferred);
+ return databaseConnection.listTriples(rsubj, rpred, robj, null, includeInferred, true);
} catch (SQLException e) {
throw new RepositoryException("database error while listing triples",e);
}
@@ -343,7 +347,6 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
// nothing to do, the database transaction is started automatically
triplesAdded = false;
triplesRemoved = false;
- deletedStatementsLog = new HashSet<Long>();
}
@Override
@@ -354,7 +357,6 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
throw new SailException("database error while committing transaction",e);
}
if(triplesAdded || triplesRemoved) {
- deletedStatementsLog.clear();
store.notifySailChanged(new SailChangedEvent() {
@Override
@@ -379,7 +381,6 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
protected void rollbackInternal() throws SailException {
try {
databaseConnection.rollback();
- deletedStatementsLog.clear();
} catch (SQLException e) {
throw new SailException("database error while rolling back transaction",e);
}
@@ -394,9 +395,9 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
if(triple.getId() != null) {
databaseConnection.deleteTriple(triple);
triplesRemoved = true;
- deletedStatementsLog.add(triple.getId());
notifyStatementRemoved(triple);
}
+ valueFactory.removeStatement(triple);
}
triples.close();
} catch(SQLException ex) {
@@ -425,9 +426,9 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
if(triple.getId() != null && triple.isInferred()) {
databaseConnection.deleteTriple(triple);
triplesRemoved = true;
- deletedStatementsLog.add(triple.getId());
notifyStatementRemoved(triple);
}
+ valueFactory.removeStatement(triple);
}
triples.close();
} catch(SQLException ex) {
@@ -439,12 +440,6 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
/**
* Removes an inferred statement from a specific context.
*
- * @param subj The subject of the statement that should be removed.
- * @param pred The predicate of the statement that should be removed.
- * @param obj The object of the statement that should be removed.
- * @param contexts The context(s) from which to remove the statements. Note that this
- * parameter is a vararg and as such is optional. If no contexts are
- * supplied the method operates on the entire repository.
* @throws org.openrdf.sail.SailException If the statement could not be removed.
* @throws IllegalStateException If the connection has been closed.
*/
@@ -453,7 +448,6 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
if(triple.getId() != null && triple.isInferred()) {
databaseConnection.deleteTriple(triple);
triplesRemoved = true;
- deletedStatementsLog.add(triple.getId());
notifyStatementRemoved(triple);
}
} catch(SQLException ex) {
@@ -610,7 +604,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
throw new IllegalArgumentException("e must not be null");
}
else {
- throw new IllegalArgumentException("Unexpected exception type: " + e.getClass());
+ throw new IllegalArgumentException("Unexpected exception type: " + e.getClass(),e);
}
}
};
@@ -631,6 +625,83 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
}
}
+ /**
+ * Return an iterator over the resources contained in this repository.
+ *
+ * @return
+ */
+ @Override
+ public RepositoryResult<Resource> getResources() throws RepositoryException {
+ try {
+ return new RepositoryResult<Resource>(new ExceptionConvertingIteration<Resource,RepositoryException>(databaseConnection.listResources()) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException(e);
+ }
+ });
+ } catch (SQLException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Return an iterator over the resources contained in this repository matching the given prefix.
+ *
+ * @return
+ */
+ @Override
+ public RepositoryResult<URI> getResources(String prefix) throws RepositoryException {
+ try {
+ return new RepositoryResult<URI>(new ExceptionConvertingIteration<URI,RepositoryException>(databaseConnection.listResources(prefix)) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException(e);
+ }
+ });
+ } catch (SQLException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Return the Sesame URI with the given uri identifier if it exists, or null if it does not exist.
+ *
+ * @param uri
+ * @return
+ */
+ @Override
+ public URI getURI(String uri) {
+ try {
+ return databaseConnection.loadUriResource(uri);
+ } catch (SQLException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Return the Sesame BNode with the given anonymous ID if it exists, or null if it does not exist.
+ *
+ * @param id
+ * @return
+ */
+ @Override
+ public BNode getBNode(String id) {
+ try {
+ return databaseConnection.loadAnonResource(id);
+ } catch (SQLException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Remove the resource given as argument from the triple store and the resource repository.
+ *
+ * @param resource
+ */
+ @Override
+ public void removeResource(Resource resource) {
+ // handled by garbage collection
+ }
protected static class KiWiEvaluationStatistics extends EvaluationStatistics {
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiStore.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiStore.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiStore.java
index 3c71e2c..4119023 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiStore.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiStore.java
@@ -18,6 +18,7 @@
package org.apache.marmotta.kiwi.sail;
import com.google.common.collect.MapMaker;
+import org.apache.marmotta.kiwi.config.KiWiConfiguration;
import org.apache.marmotta.kiwi.model.caching.IntArray;
import org.apache.marmotta.kiwi.persistence.KiWiDialect;
import org.apache.marmotta.kiwi.persistence.KiWiPersistence;
@@ -91,20 +92,23 @@ public class KiWiStore extends NotifyingSailBase {
protected ConcurrentMap<IntArray,Statement> tripleRegistry;
public KiWiStore(KiWiPersistence persistence, String defaultContext, String inferredContext) {
- this.persistence = persistence;
- this.defaultContext = defaultContext;
+ this.persistence = persistence;
+ this.defaultContext = defaultContext;
this.nodeLock = new ReentrantLock();
this.tripleLock = new ReentrantLock();
this.inferredContext = inferredContext;
-
- tripleRegistry = new MapMaker().weakValues().makeMap();
+
}
+ @Deprecated
public KiWiStore(String name, String jdbcUrl, String db_user, String db_password, KiWiDialect dialect, String defaultContext, String inferredContext) {
- this(new KiWiPersistence(name,jdbcUrl,db_user,db_password,dialect), defaultContext, inferredContext);
+ this(new KiWiConfiguration(name,jdbcUrl,db_user,db_password,dialect, defaultContext, inferredContext));
}
+ public KiWiStore(KiWiConfiguration configuration) {
+ this(new KiWiPersistence(configuration), configuration.getDefaultContext(), configuration.getInferredContext());
+ }
/**
* Do store-specific operations to initialize the store. The default
@@ -112,9 +116,11 @@ public class KiWiStore extends NotifyingSailBase {
*/
@Override
protected void initializeInternal() throws SailException {
+ tripleRegistry = new MapMaker().weakValues().makeMap();
+
try {
- persistence.initDatabase();
persistence.initialise();
+ persistence.initDatabase();
initialized = true;
} catch (SQLException e) {
@@ -168,15 +174,19 @@ public class KiWiStore extends NotifyingSailBase {
protected void shutDownInternal() throws SailException {
closeValueFactory();
persistence.shutdown();
+ tripleRegistry = null;
+ initialized = false;
}
/**
* In case there is a value factory managed by this repository directly, close it (and the underlying database
* connection)
*/
- public void closeValueFactory() {
+ public synchronized void closeValueFactory() {
if(repositoryValueFactory != null) {
+ repositoryValueFactory.close();
repositoryValueFactory = null;
+ persistence.setValueFactory(null);
}
}
@@ -197,11 +207,31 @@ public class KiWiStore extends NotifyingSailBase {
* @return a ValueFactory object for this Sail object.
*/
@Override
- public ValueFactory getValueFactory() {
+ public synchronized ValueFactory getValueFactory() {
if(repositoryValueFactory == null) {
repositoryValueFactory = new KiWiValueFactory(this, defaultContext);
+ persistence.setValueFactory(repositoryValueFactory);
}
return repositoryValueFactory;
}
+ /**
+ * Manually call the garbage collector for the triple store. Otherwise it will run every hour.
+ */
+ public void garbageCollect() throws SailException {
+ try {
+ persistence.garbageCollect();
+ } catch (SQLException e) {
+ throw new SailException("error calling garbage collector",e);
+ }
+ }
+
+
+ public boolean checkConsistency() throws SailException {
+ try {
+ return persistence.checkConsistency();
+ } catch (SQLException e) {
+ throw new SailException("error calling consistency check",e);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java
index 22038f6..9ec70fb 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java
@@ -17,35 +17,26 @@
*/
package org.apache.marmotta.kiwi.sail;
-import com.google.common.collect.MapMaker;
-import org.apache.commons.lang.LocaleUtils;
+import org.apache.commons.lang3.LocaleUtils;
+import org.apache.marmotta.commons.locking.ObjectLocks;
import org.apache.marmotta.commons.sesame.model.LiteralCommons;
+import org.apache.marmotta.commons.sesame.model.LiteralKey;
import org.apache.marmotta.commons.sesame.model.Namespaces;
import org.apache.marmotta.commons.util.DateUtils;
import org.apache.marmotta.kiwi.model.caching.IntArray;
import org.apache.marmotta.kiwi.model.rdf.*;
import org.apache.marmotta.kiwi.persistence.KiWiConnection;
-import org.openrdf.model.BNode;
-import org.openrdf.model.Literal;
-import org.openrdf.model.Resource;
-import org.openrdf.model.Statement;
-import org.openrdf.model.URI;
-import org.openrdf.model.Value;
-import org.openrdf.model.ValueFactory;
+import org.openrdf.model.*;
import org.openrdf.model.impl.ContextStatementImpl;
-import org.openrdf.model.impl.StatementImpl;
-import org.openrdf.repository.RepositoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.sql.SQLException;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Random;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Add file description here!
@@ -58,7 +49,6 @@ public class KiWiValueFactory implements ValueFactory {
private Random anonIdGenerator;
-
/**
* This is a hash map for storing references to resources that have not yet been persisted. It is used e.g. when
* one or more transactions are currently active and request the creation of same resource several times
@@ -76,75 +66,88 @@ public class KiWiValueFactory implements ValueFactory {
private KiWiStore store;
- private ReentrantLock nodeLock;
- private ReentrantLock tripleLock;
- private ConcurrentMap<String,ReentrantLock> resourceLocks;
- private ConcurrentMap<Object,ReentrantLock> literalLocks;
+ private ObjectLocks resourceLocks;
+ private ObjectLocks literalLocks;
private String defaultContext;
+ private boolean batchCommit;
+
+ private int batchSize = 1000;
+
+ // the list containing the in-memory nodes that need to be committed later
+ private List<KiWiNode> nodeBatch;
+
+ // a quick lookup allowing to lookup nodes while they are not yet in the database
+ private Map<String,KiWiUriResource> batchUriLookup;
+ private Map<String,KiWiAnonResource> batchBNodeLookup;
+ private Map<String,KiWiLiteral> batchLiteralLookup;
+
+ private int poolSize = 4;
+ private int poolPosition = 0;
+
+ private ArrayList<KiWiConnection> pooledConnections;
+
+
+ private ReentrantReadWriteLock commitLock = new ReentrantReadWriteLock();
+
public KiWiValueFactory(KiWiStore store, String defaultContext) {
- nodeLock = store.nodeLock;
- tripleLock = store.tripleLock;
- resourceLocks = new MapMaker().weakKeys().weakValues().makeMap();
- literalLocks = new MapMaker().weakKeys().weakValues().makeMap();
+ resourceLocks = new ObjectLocks();
+ literalLocks = new ObjectLocks();
anonIdGenerator = new Random();
tripleRegistry = store.tripleRegistry;
this.store = store;
this.defaultContext = defaultContext;
- }
- protected KiWiConnection aqcuireConnection() {
+ // batch commits
+ this.nodeBatch = Collections.synchronizedList(new ArrayList<KiWiNode>(batchSize));
+
+ this.batchCommit = store.getPersistence().getConfiguration().isBatchCommit();
+ this.batchSize = store.getPersistence().getConfiguration().getBatchSize();
+
+ this.batchUriLookup = new ConcurrentHashMap<String,KiWiUriResource>();
+ this.batchBNodeLookup = new ConcurrentHashMap<String, KiWiAnonResource>();
+ this.batchLiteralLookup = new ConcurrentHashMap<String,KiWiLiteral>();
+
+ this.pooledConnections = new ArrayList<>(poolSize);
try {
- KiWiConnection connection = store.getPersistence().getConnection();
- return connection;
- } catch(SQLException ex) {
- log.error("could not acquire database connection",ex);
- throw new RuntimeException(ex);
+ for(int i = 0; i<poolSize ; i++) {
+ pooledConnections.add(store.getPersistence().getConnection());
+ }
+ } catch (SQLException e) {
+ log.error("error initialising value factory connection pool",e);
}
}
- protected void releaseConnection(KiWiConnection con) {
+ protected KiWiConnection aqcuireConnection() {
try {
- con.commit();
- con.close();
- } catch (SQLException ex) {
- log.error("could not release database connection", ex);
+ if(batchCommit) {
+ return pooledConnections.get(poolPosition++ % poolSize);
+ } else {
+ return store.getPersistence().getConnection();
+ }
+ } catch(SQLException ex) {
+ log.error("could not acquire database connection", ex);
throw new RuntimeException(ex);
}
}
- protected ReentrantLock acquireResourceLock(String uri) {
- ReentrantLock lock;
- synchronized (resourceLocks) {
- lock = resourceLocks.get(uri);
- if(lock == null) {
- lock = new ReentrantLock();
- resourceLocks.put(uri,lock);
+ protected void releaseConnection(KiWiConnection con) {
+ if(!batchCommit) {
+ try {
+ con.commit();
+ con.close();
+ } catch (SQLException ex) {
+ log.error("could not release database connection", ex);
+ throw new RuntimeException(ex);
}
}
- lock.lock();
-
- return lock;
}
- protected ReentrantLock acquireLiteralLock(Object value) {
- ReentrantLock lock;
- synchronized (literalLocks) {
- lock = literalLocks.get(value);
- if(lock == null) {
- lock = new ReentrantLock();
- literalLocks.put(value,lock);
- }
- }
- lock.lock();
-
- return lock;
- }
/**
* Creates a new bNode.
*
@@ -163,27 +166,63 @@ public class KiWiValueFactory implements ValueFactory {
*/
@Override
public URI createURI(String uri) {
+ commitLock.readLock().lock();
+
+ resourceLocks.lock(uri);
- ReentrantLock lock = acquireResourceLock(uri);
- KiWiConnection connection = aqcuireConnection();
try {
- // first look in the registry for newly created resources if the resource has already been created and
- // is still volatile
- KiWiUriResource result = connection.loadUriResource(uri);
+ KiWiUriResource result = batchUriLookup.get(uri);
- if(result == null) {
- result = new KiWiUriResource(uri);
- connection.storeNode(result);
- }
+ if(result != null) {
+ return result;
+ } else {
- return result;
- } catch (SQLException e) {
- log.error("database error, could not load URI resource",e);
- throw new IllegalStateException("database error, could not load URI resource",e);
+ KiWiConnection connection = aqcuireConnection();
+ try {
+ // first look in the registry for newly created resources if the resource has already been created and
+ // is still volatile
+ result = connection.loadUriResource(uri);
+
+ if(result == null) {
+ result = new KiWiUriResource(uri);
+
+ if(batchCommit) {
+ result.setId(connection.getNodeId());
+ batchUriLookup.put(uri, result);
+
+ nodeBatch.add(result);
+
+ } else {
+ connection.storeNode(result, false);
+ }
+
+ }
+ if(result.getId() == null) {
+ log.error("node ID is null!");
+ }
+
+ return result;
+ } catch (SQLException e) {
+ log.error("database error, could not load URI resource",e);
+ throw new IllegalStateException("database error, could not load URI resource",e);
+ } finally {
+ releaseConnection(connection);
+ }
+ }
} finally {
- releaseConnection(connection);
- lock.unlock();
+ resourceLocks.unlock(uri);
+ commitLock.readLock().unlock();
+
+ try {
+ if(nodeBatch.size() >= batchSize) {
+ flushBatch();
+ }
+ } catch (SQLException e) {
+ log.error("database error, could not load URI resource",e);
+ throw new IllegalStateException("database error, could not load URI resource",e);
+ }
}
+
}
/**
@@ -213,25 +252,56 @@ public class KiWiValueFactory implements ValueFactory {
*/
@Override
public BNode createBNode(String nodeID) {
- nodeLock.lock();
- KiWiConnection connection = aqcuireConnection();
+ commitLock.readLock().lock();
+ resourceLocks.lock(nodeID);
+
try {
- // first look in the registry for newly created resources if the resource has already been created and
- // is still volatile
- KiWiAnonResource result = connection.loadAnonResource(nodeID);
+ KiWiAnonResource result = batchBNodeLookup.get(nodeID);
- if(result == null) {
- result = new KiWiAnonResource(nodeID);
- connection.storeNode(result);
+ if(result != null) {
+ return result;
+ } else {
+ KiWiConnection connection = aqcuireConnection();
+ try {
+ // first look in the registry for newly created resources if the resource has already been created and
+ // is still volatile
+ result = connection.loadAnonResource(nodeID);
+
+ if(result == null) {
+ result = new KiWiAnonResource(nodeID);
+
+ if(batchCommit) {
+ result.setId(connection.getNodeId());
+ nodeBatch.add(result);
+ batchBNodeLookup.put(nodeID,result);
+ } else {
+ connection.storeNode(result, false);
+ }
+ }
+ if(result.getId() == null) {
+ log.error("node ID is null!");
+ }
+
+ return result;
+ } catch (SQLException e) {
+ log.error("database error, could not load anonymous resource",e);
+ throw new IllegalStateException("database error, could not load anonymous resource",e);
+ } finally {
+ releaseConnection(connection);
+ }
}
-
- return result;
- } catch (SQLException e) {
- log.error("database error, could not load anonymous resource",e);
- throw new IllegalStateException("database error, could not load anonymous resource",e);
} finally {
- releaseConnection(connection);
- nodeLock.unlock();
+ resourceLocks.unlock(nodeID);
+ commitLock.readLock().unlock();
+
+ try {
+ if(nodeBatch.size() >= batchSize) {
+ flushBatch();
+ }
+ } catch (SQLException e) {
+ log.error("database error, could not load URI resource",e);
+ throw new IllegalStateException("database error, could not load URI resource",e);
+ }
}
}
@@ -260,12 +330,11 @@ public class KiWiValueFactory implements ValueFactory {
* @return a typed literal representation of the supplied object.
* @since 2.7.0
*/
- @Override
public Literal createLiteral(Object object) {
if(object instanceof XMLGregorianCalendar) {
return createLiteral((XMLGregorianCalendar)object);
} else {
- return createLiteral(object,null,null);
+ return createLiteral(object,null,LiteralCommons.getXSDType(object.getClass()));
}
}
@@ -276,7 +345,9 @@ public class KiWiValueFactory implements ValueFactory {
*/
@Override
public Literal createLiteral(String label) {
- return createLiteral(label, null, LiteralCommons.getXSDType(String.class));
+ // FIXME: MARMOTTA-39 (no default datatype before RDF-1.1)
+ // return createLiteral(label, null, LiteralCommons.getXSDType(String.class));
+ return createLiteral(label, null, null);
}
/**
@@ -288,7 +359,9 @@ public class KiWiValueFactory implements ValueFactory {
*/
@Override
public Literal createLiteral(String label, String language) {
- return createLiteral(label,language,LiteralCommons.getRDFLangStringType());
+ // FIXME: MARMOTTA-39 (no rdf:langString before RDF-1.1)
+ // return createLiteral(label,language,LiteralCommons.getRDFLangStringType());
+ return createLiteral(label, language, null);
}
/**
@@ -315,112 +388,173 @@ public class KiWiValueFactory implements ValueFactory {
* @return
*/
private <T> KiWiLiteral createLiteral(T value, String lang, String type) {
- if (lang != null) {
- type = LiteralCommons.getRDFLangStringType();
- } else if(type == null) {
- type = LiteralCommons.getXSDType(value.getClass());
+ commitLock.readLock().lock();
+ Locale locale;
+ if(lang != null) {
+ try {
+ Locale.Builder builder = new Locale.Builder();
+ builder.setLanguageTag(lang);
+ locale = builder.build();
+ } catch (IllformedLocaleException ex) {
+ log.warn("malformed language literal (language: {})", lang);
+ locale = null;
+ lang = null;
+ }
+ } else {
+ locale = null;
}
- KiWiLiteral result = null;
+ if (lang != null) {
+ // FIXME: MARMOTTA-39 (no rdf:langString)
+ // type = LiteralCommons.getRDFLangStringType();
+ } else if (type == null) {
+ // FIXME: MARMOTTA-39 (no default datatype before RDF-1.1)
+ // type = LiteralCommons.getXSDType(value.getClass());
+ }
+ String key = LiteralCommons.createCacheKey(value.toString(),locale,type);
+ LiteralKey lkey = new LiteralKey(value,type,lang);
- final KiWiUriResource rtype = (KiWiUriResource)createURI(type);
- final Locale locale;
- if(lang != null) {
- locale = LocaleUtils.toLocale(lang);
- } else
- locale = null;
+ literalLocks.lock(lkey);
- ReentrantLock lock = acquireLiteralLock(value);
- KiWiConnection connection = aqcuireConnection();
try {
+ KiWiLiteral result = batchLiteralLookup.get(key);
- // differentiate between the different types of the value
- if(value instanceof Date || type.equals(Namespaces.NS_XSD+"dateTime")) {
- // parse if necessary
- final Date dvalue;
- if(value instanceof Date) {
- dvalue = (Date)value;
- } else {
- dvalue = DateUtils.parseDate(value.toString());
- }
-
- result = connection.loadLiteral(dvalue);
-
- if(result == null) {
- result= new KiWiDateLiteral(dvalue, rtype);
- }
- } else if(Integer.class.equals(value.getClass()) || int.class.equals(value.getClass()) ||
- Long.class.equals(value.getClass()) || long.class.equals(value.getClass()) ||
- type.equals(Namespaces.NS_XSD+"integer") || type.equals(Namespaces.NS_XSD+"long")) {
- long ivalue = 0;
- if(Integer.class.equals(value.getClass()) || int.class.equals(value.getClass())) {
- ivalue = (Integer)value;
- } else if(Long.class.equals(value.getClass()) || long.class.equals(value.getClass())) {
- ivalue = (Long)value;
- } else {
- ivalue = Long.parseLong(value.toString());
- }
-
-
- result = connection.loadLiteral(ivalue);
-
- if(result == null) {
- result= new KiWiIntLiteral(ivalue, rtype);
- }
- } else if(Double.class.equals(value.getClass()) || double.class.equals(value.getClass()) ||
- Float.class.equals(value.getClass()) || float.class.equals(value.getClass()) ||
- type.equals(Namespaces.NS_XSD+"double") || type.equals(Namespaces.NS_XSD+"float")) {
- double dvalue = 0.0;
- if(Float.class.equals(value.getClass()) || float.class.equals(value.getClass())) {
- dvalue = (Float)value;
- } else if(Double.class.equals(value.getClass()) || double.class.equals(value.getClass())) {
- dvalue = (Double)value;
- } else {
- dvalue = Double.parseDouble(value.toString());
- }
-
-
- result = connection.loadLiteral(dvalue);
-
- if(result == null) {
- result= new KiWiDoubleLiteral(dvalue, rtype);
- }
- } else if(Boolean.class.equals(value.getClass()) || boolean.class.equals(value.getClass()) ||
- type.equals(Namespaces.NS_XSD+"boolean")) {
- boolean bvalue = false;
- if(Boolean.class.equals(value.getClass()) || boolean.class.equals(value.getClass())) {
- bvalue = (Boolean)value;
- } else {
- bvalue = Boolean.parseBoolean(value.toString());
- }
-
-
- result = connection.loadLiteral(bvalue);
-
- if(result == null) {
- result= new KiWiBooleanLiteral(bvalue, rtype);
- }
+ if(result != null) {
+ return result;
} else {
- result = connection.loadLiteral(value.toString(), lang, rtype);
-
- if(result == null) {
- result = new KiWiStringLiteral(value.toString(), locale, rtype);
+ final KiWiUriResource rtype = type==null?null:(KiWiUriResource)createURI(type);
+
+ final KiWiConnection connection = aqcuireConnection();
+ try {
+
+ try {
+ // differentiate between the different types of the value
+ if (type == null) {
+ // FIXME: MARMOTTA-39 (this is to avoid a NullPointerException in the following if-clauses)
+ result = connection.loadLiteral(value.toString(), lang, rtype);
+
+ if(result == null) {
+ result = new KiWiStringLiteral(value.toString(), locale, rtype);
+ }
+ } else if(value instanceof Date || type.equals(Namespaces.NS_XSD+"dateTime")) {
+ // parse if necessary
+ final Date dvalue;
+ if(value instanceof Date) {
+ dvalue = (Date)value;
+ } else {
+ dvalue = DateUtils.parseDate(value.toString());
+ }
+
+ result = connection.loadLiteral(dvalue);
+
+ if(result == null) {
+ result= new KiWiDateLiteral(dvalue, rtype);
+ }
+ } else if(Integer.class.equals(value.getClass()) || int.class.equals(value.getClass()) ||
+ Long.class.equals(value.getClass()) || long.class.equals(value.getClass()) ||
+ type.equals(Namespaces.NS_XSD+"integer") || type.equals(Namespaces.NS_XSD+"long")) {
+ long ivalue = 0;
+ if(Integer.class.equals(value.getClass()) || int.class.equals(value.getClass())) {
+ ivalue = (Integer)value;
+ } else if(Long.class.equals(value.getClass()) || long.class.equals(value.getClass())) {
+ ivalue = (Long)value;
+ } else {
+ ivalue = Long.parseLong(value.toString());
+ }
+
+
+ result = connection.loadLiteral(ivalue);
+
+ if(result == null) {
+ result= new KiWiIntLiteral(ivalue, rtype);
+ }
+ } else if(Double.class.equals(value.getClass()) || double.class.equals(value.getClass()) ||
+ Float.class.equals(value.getClass()) || float.class.equals(value.getClass()) ||
+ type.equals(Namespaces.NS_XSD+"double") || type.equals(Namespaces.NS_XSD+"float")) {
+ double dvalue = 0.0;
+ if(Float.class.equals(value.getClass()) || float.class.equals(value.getClass())) {
+ dvalue = (Float)value;
+ } else if(Double.class.equals(value.getClass()) || double.class.equals(value.getClass())) {
+ dvalue = (Double)value;
+ } else {
+ dvalue = Double.parseDouble(value.toString());
+ }
+
+
+ result = connection.loadLiteral(dvalue);
+
+ if(result == null) {
+ result= new KiWiDoubleLiteral(dvalue, rtype);
+ }
+ } else if(Boolean.class.equals(value.getClass()) || boolean.class.equals(value.getClass()) ||
+ type.equals(Namespaces.NS_XSD+"boolean")) {
+ boolean bvalue = false;
+ if(Boolean.class.equals(value.getClass()) || boolean.class.equals(value.getClass())) {
+ bvalue = (Boolean)value;
+ } else {
+ bvalue = Boolean.parseBoolean(value.toString());
+ }
+
+
+ result = connection.loadLiteral(bvalue);
+
+ if(result == null) {
+ result= new KiWiBooleanLiteral(bvalue, rtype);
+ }
+ } else {
+ result = connection.loadLiteral(value.toString(), lang, rtype);
+
+ if(result == null) {
+ result = new KiWiStringLiteral(value.toString(), locale, rtype);
+ }
+ }
+ } catch(IllegalArgumentException ex) {
+ // malformed number or date
+ log.warn("malformed argument for typed literal of type {}: {}", rtype.stringValue(), value);
+ KiWiUriResource mytype = (KiWiUriResource)createURI(Namespaces.NS_XSD+"string");
+
+ result = connection.loadLiteral(value.toString(), lang, mytype);
+
+ if(result == null) {
+ result = new KiWiStringLiteral(value.toString(), locale, mytype);
+ }
+
+ }
+
+ if(result.getId() == null) {
+ if(batchCommit) {
+ result.setId(connection.getNodeId());
+ batchLiteralLookup.put(key, result);
+
+ nodeBatch.add(result);
+ } else {
+ connection.storeNode(result, false);
+ }
+ }
+
+ return result;
+
+
+ } catch (SQLException e) {
+ log.error("database error, could not load literal",e);
+ throw new IllegalStateException("database error, could not load literal",e);
+ } finally {
+ releaseConnection(connection);
}
}
+ } finally {
+ literalLocks.unlock(lkey);
+ commitLock.readLock().unlock();
- if(result.getId() == null) {
- connection.storeNode(result);
+ try {
+ if(nodeBatch.size() >= batchSize) {
+ flushBatch();
+ }
+ } catch (SQLException e) {
+ log.error("database error, could not load URI resource",e);
+ throw new IllegalStateException("database error, could not load URI resource",e);
}
-
- return result;
-
- } catch (SQLException e) {
- log.error("database error, could not load literal",e);
- throw new IllegalStateException("database error, could not load literal",e);
- } finally {
- releaseConnection(connection);
- lock.unlock();
}
}
@@ -532,7 +666,11 @@ public class KiWiValueFactory implements ValueFactory {
*/
@Override
public Statement createStatement(Resource subject, URI predicate, Value object) {
- return createStatement(subject, predicate, object, createURI(defaultContext));
+ if(defaultContext != null) {
+ return createStatement(subject, predicate, object, createURI(defaultContext));
+ } else {
+ return createStatement(subject, predicate, object, null);
+ }
}
/**
@@ -548,41 +686,6 @@ public class KiWiValueFactory implements ValueFactory {
@Override
public Statement createStatement(Resource subject, URI predicate, Value object, Resource context) {
return new ContextStatementImpl(subject,predicate,object,context);
- /*
- tripleLock.lock();
- KiWiConnection connection = aqcuireConnection();
- try {
- IntArray cacheKey = IntArray.createSPOCKey(subject,predicate,object,context);
- Statement result = tripleRegistry.get(cacheKey);
- if(result == null || ((KiWiTriple)result).isDeleted()) {
- KiWiResource ksubject = convert(subject);
- KiWiUriResource kpredicate = convert(predicate);
- KiWiNode kobject = convert(object);
- KiWiResource kcontext = convert(context);
-
- // test if the triple already exists in the database; if yes, return it
- List<Statement> triples = connection.listTriples(ksubject,kpredicate,kobject,kcontext,true).asList();
- if(triples.size() == 1) {
- result = triples.get(0);
- } else {
- result = new KiWiTriple(ksubject,kpredicate,kobject,kcontext);
- ((KiWiTriple)result).setMarkedForReasoning(true);
- }
-
- tripleRegistry.put(cacheKey,result);
- }
- return result;
- } catch (SQLException e) {
- log.error("database error, could not load triple", e);
- throw new IllegalStateException("database error, could not load triple",e);
- } catch (RepositoryException e) {
- log.error("database error, could not load triple", e);
- throw new IllegalStateException("database error, could not load triple",e);
- } finally {
- releaseConnection(connection);
- tripleLock.unlock();
- }
- */
}
/**
@@ -597,22 +700,19 @@ public class KiWiValueFactory implements ValueFactory {
* @return The created statement.
*/
public Statement createStatement(Resource subject, URI predicate, Value object, Resource context, KiWiConnection connection) {
- IntArray cacheKey = IntArray.createSPOCKey(subject,predicate,object,context);
- Statement result = tripleRegistry.get(cacheKey);
+ IntArray cacheKey = IntArray.createSPOCKey(subject, predicate, object, context);
+ KiWiTriple result = (KiWiTriple)tripleRegistry.get(cacheKey);
try {
- if(result == null || ((KiWiTriple)result).isDeleted()) {
+ if(result == null || result.isDeleted()) {
KiWiResource ksubject = convert(subject);
KiWiUriResource kpredicate = convert(predicate);
KiWiNode kobject = convert(object);
KiWiResource kcontext = convert(context);
- // test if the triple already exists in the database; if yes, return it
- List<Statement> triples = connection.listTriples(ksubject,kpredicate,kobject,kcontext,true).asList();
- if(triples.size() == 1) {
- result = triples.get(0);
- } else {
- result = new KiWiTriple(ksubject,kpredicate,kobject,kcontext);
- ((KiWiTriple)result).setMarkedForReasoning(true);
+ result = new KiWiTriple(ksubject,kpredicate,kobject,kcontext);
+ result.setId(connection.getTripleId(ksubject,kpredicate,kobject,kcontext,true));
+ if(result.getId() == null) {
+ result.setMarkedForReasoning(true);
}
tripleRegistry.put(cacheKey,result);
@@ -621,12 +721,18 @@ public class KiWiValueFactory implements ValueFactory {
} catch (SQLException e) {
log.error("database error, could not load triple", e);
throw new IllegalStateException("database error, could not load triple",e);
- } catch (RepositoryException e) {
- log.error("database error, could not load triple", e);
- throw new IllegalStateException("database error, could not load triple",e);
}
}
+ /**
+ * Remove a statement from the triple registry. Called when the statement is deleted and the transaction commits.
+ * @param triple
+ */
+ protected void removeStatement(KiWiTriple triple) {
+ IntArray cacheKey = IntArray.createSPOCKey(triple.getSubject(), triple.getPredicate(), triple.getObject(), triple.getContext());
+ tripleRegistry.remove(cacheKey);
+ triple.setDeleted(true);
+ }
public KiWiResource convert(Resource r) {
@@ -654,4 +760,87 @@ public class KiWiValueFactory implements ValueFactory {
}
}
+
+ public boolean isBatchCommit() {
+ return batchCommit;
+ }
+
+ public void setBatchCommit(boolean batchCommit) {
+ this.batchCommit = batchCommit;
+ }
+
+ public int getBatchSize() {
+ return batchSize;
+ }
+
+ public void setBatchSize(int batchSize) {
+ this.batchSize = batchSize;
+ }
+
+
+ /**
+ * Immediately flush the batch to the database using the value factory's connection. The method expects the
+ * underlying connection to start and commit the node batch.
+ */
+ public void flushBatch() throws SQLException {
+ KiWiConnection con = aqcuireConnection();
+ try {
+ flushBatch(con);
+ } finally {
+ releaseConnection(con);
+ }
+
+ }
+
+
+ /**
+ * Immediately flush the batch to the database. The method expects the underlying connection to start and commit
+ * the node batch.
+ */
+ public void flushBatch(KiWiConnection con) throws SQLException {
+ commitLock.writeLock().lock();
+ try {
+ if(batchCommit && nodeBatch.size() > 0) {
+ List<KiWiNode> processed = this.nodeBatch;
+ this.nodeBatch = Collections.synchronizedList(new ArrayList<KiWiNode>(batchSize));
+
+ con.startNodeBatch();
+
+ for(KiWiNode n : processed) {
+ con.storeNode(n,true);
+ }
+ batchLiteralLookup.clear();
+ batchUriLookup.clear();
+ batchBNodeLookup.clear();
+
+ con.commitNodeBatch();
+ }
+ } finally {
+ commitLock.writeLock().unlock();
+ }
+ }
+
+ public void close() {
+
+ for(KiWiConnection con : pooledConnections) {
+ try {
+ if(!con.isClosed()) {
+ if(batchCommit && nodeBatch.size() > 0) {
+ try {
+ flushBatch(con);
+ } catch (SQLException e) {
+ log.error("error while flushing node batch",e);
+ }
+ }
+
+ con.commit();
+ con.close();
+ }
+ } catch (SQLException e) {
+ log.warn("could not close value factory connection: {}",e.getMessage());
+ }
+ }
+ }
+
+
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/resources/ehcache-kiwi.xml
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/ehcache-kiwi.xml b/libraries/kiwi/kiwi-triplestore/src/main/resources/ehcache-kiwi.xml
index 179f24d..9d27ef1 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/resources/ehcache-kiwi.xml
+++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/ehcache-kiwi.xml
@@ -149,7 +149,7 @@ are "on" and "off". The default is "autodetect".
a cache from database ID to KiWiNode; should be very large since this kind of lookup is a very frequent operation
-->
<cache name="node-cache"
- maxElementsInMemory="500000"
+ maxElementsInMemory="5000000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU"/>
@@ -159,7 +159,7 @@ are "on" and "off". The default is "autodetect".
from the database by avoiding reconstructing each triple from the database result
-->
<cache name="triple-cache"
- maxElementsInMemory="100000"
+ maxElementsInMemory="500000"
overflowToDisk="false"
timeToLiveSeconds="3600"
memoryStoreEvictionPolicy="LFU"/>
@@ -176,7 +176,7 @@ are "on" and "off". The default is "autodetect".
<!-- a cache from URI to KiWiUriResource -->
<cache name="uri-cache"
- maxElementsInMemory="50000"
+ maxElementsInMemory="500000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU"/>
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/create_base_tables.sql
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/create_base_tables.sql b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/create_base_tables.sql
index 0e4fed5..3493187 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/create_base_tables.sql
+++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/create_base_tables.sql
@@ -20,7 +20,7 @@ CREATE SEQUENCE seq_namespaces;
CREATE TABLE nodes (
id bigint NOT NULL,
ntype char(8) NOT NULL,
- svalue varchar(65536) NOT NULL,
+ svalue varchar(2147483647) NOT NULL,
dvalue double precision,
ivalue bigint,
tvalue timestamp,
@@ -36,7 +36,7 @@ CREATE TABLE triples (
subject bigint NOT NULL REFERENCES nodes(id),
predicate bigint NOT NULL REFERENCES nodes(id),
object bigint NOT NULL REFERENCES nodes(id),
- context bigint NOT NULL REFERENCES nodes(id),
+ context bigint REFERENCES nodes(id),
creator bigint REFERENCES nodes(id),
inferred boolean DEFAULT false,
deleted boolean DEFAULT false,
@@ -66,18 +66,13 @@ CREATE TABLE metadata (
CREATE INDEX idx_node_content ON nodes(svalue);
CREATE INDEX idx_literal_lang ON nodes(lang);
-CREATE INDEX idx_triples_s ON triples(subject);
-CREATE INDEX idx_triples_o ON triples(object);
-CREATE INDEX idx_triples_sp ON triples(subject,predicate);
-CREATE INDEX idx_triples_po ON triples(predicate,object);
CREATE INDEX idx_triples_spo ON triples(subject,predicate,object);
-CREATE INDEX idx_triples_cs ON triples(context,subject);
-CREATE INDEX idx_triples_csp ON triples(context,subject,predicate);
+CREATE INDEX idx_triples_op ON triples(object,predicate);
CREATE INDEX idx_triples_cspo ON triples(context,subject,predicate,object);
CREATE INDEX idx_namespaces_uri ON namespaces(uri);
CREATE INDEX idx_namespaces_prefix ON namespaces(prefix);
-- insert initial metadata
-INSERT INTO metadata(mkey,mvalue) VALUES ('version','1');
+INSERT INTO metadata(mkey,mvalue) VALUES ('version','2');
INSERT INTO metadata(mkey,mvalue) VALUES ('created',FORMATDATETIME(now(),'yyyy-MM-dd HH:mm:ss z','en') );
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/drop_base_tables.sql
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/drop_base_tables.sql b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/drop_base_tables.sql
index bf3d7e4..41ca5f7 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/drop_base_tables.sql
+++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/drop_base_tables.sql
@@ -16,13 +16,8 @@
DROP INDEX IF EXISTS idx_node_content;
DROP INDEX IF EXISTS idx_literal_lang;
-DROP INDEX IF EXISTS idx_triples_s;
-DROP INDEX IF EXISTS idx_triples_o;
-DROP INDEX IF EXISTS idx_triples_sp;
-DROP INDEX IF EXISTS idx_triples_po;
+DROP INDEX IF EXISTS idx_triples_op;
DROP INDEX IF EXISTS idx_triples_spo;
-DROP INDEX IF EXISTS idx_triples_cs;
-DROP INDEX IF EXISTS idx_triples_csp;
DROP INDEX IF EXISTS idx_triples_cspo;
DROP INDEX IF EXISTS idx_namespaces_uri;