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;