You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2013/03/21 14:58:28 UTC

[2/4] git commit: fix bug in KiWiValueFactory and improve concurrency performance

fix bug in KiWiValueFactory and improve concurrency performance


Project: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/commit/c4ca14f0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/tree/c4ca14f0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/diff/c4ca14f0

Branch: refs/heads/master
Commit: c4ca14f0af00bd79e2ab5b03f2cde7b2a292f7f1
Parents: ca4cc05
Author: Sebastian Schaffert <ss...@apache.org>
Authored: Thu Mar 21 14:55:54 2013 +0100
Committer: Sebastian Schaffert <ss...@apache.org>
Committed: Thu Mar 21 14:55:54 2013 +0100

----------------------------------------------------------------------
 .../persistence/KiWiReasoningConnection.java       |   41 ++-
 .../persistence/KiWiReasoningPersistence.java      |    2 +-
 .../kiwi/model/collection/WeakValueMap.java        |  357 ---------------
 .../marmotta/kiwi/persistence/KiWiConnection.java  |  148 ++++++-
 .../marmotta/kiwi/persistence/KiWiPersistence.java |    8 +-
 .../marmotta/kiwi/sail/KiWiSailConnection.java     |   18 +-
 .../org/apache/marmotta/kiwi/sail/KiWiStore.java   |    5 -
 .../marmotta/kiwi/sail/KiWiValueFactory.java       |   51 ++-
 .../kiwi/persistence/h2/statements.properties      |    1 +
 .../kiwi/persistence/mysql/statements.properties   |    1 +
 .../kiwi/persistence/pgsql/statements.properties   |    1 +
 .../apache/marmotta/kiwi/test/RepositoryTest.java  |   56 +++
 .../persistence/KiWiVersioningConnection.java      |   24 +-
 .../persistence/KiWiVersioningPersistence.java     |    2 +-
 14 files changed, 319 insertions(+), 396 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningConnection.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningConnection.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningConnection.java
index ce041e7..94daf8a 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningConnection.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningConnection.java
@@ -29,6 +29,7 @@ import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
 import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
 import org.apache.marmotta.kiwi.persistence.KiWiConnection;
 import org.apache.marmotta.kiwi.persistence.KiWiDialect;
+import org.apache.marmotta.kiwi.persistence.KiWiPersistence;
 import org.apache.marmotta.kiwi.persistence.util.ResultSetIteration;
 import org.apache.marmotta.kiwi.persistence.util.ResultTransformerFunction;
 import org.apache.marmotta.kiwi.reasoner.model.program.Field;
@@ -75,8 +76,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
 
     private Cache ruleIdCache;
 
-    public KiWiReasoningConnection(Connection connection, KiWiDialect dialect, KiWiCacheManager cacheManager, ValueFactory valueFactory) throws SQLException {
-        super(connection, dialect, cacheManager);
+    public KiWiReasoningConnection(KiWiPersistence persistence, KiWiDialect dialect, KiWiCacheManager cacheManager, ValueFactory valueFactory) throws SQLException {
+        super(persistence, dialect, cacheManager);
 
         this.valueFactory = valueFactory;
         this.ruleIdCache = getCacheManager().getCacheByName("reasoning-rule-id");
@@ -96,6 +97,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         // first create a new entry in the rules table
         rule.setId(getNextSequence("seq.rules"));
 
@@ -125,6 +128,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
         if(cached != null) {
             return (Rule) cached.getObjectValue();
         } else {
+            requireJDBCConnection();
+
             // load namespaces if they are not yet given
             if(namespaces == null) {
                 namespaces = new HashMap<String, String>();
@@ -166,6 +171,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      */
     public CloseableIteration<Rule,SQLException> loadRulesByProgram(long programId, final Map<String, String> namespaces) throws SQLException, ParseException {
 
+        requireJDBCConnection();
+
         PreparedStatement loadRule = getPreparedStatement("rules.load_by_program");
         synchronized (loadRule) {
             loadRule.setLong(1,programId);
@@ -218,6 +225,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         PreparedStatement deleteRule = getPreparedStatement("rules.delete_by_id");
         synchronized (deleteRule) {
             deleteRule.setLong(1, rule.getId());
@@ -242,6 +251,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
             throw new SQLException("Program already stored in the database");
         }
 
+        requireJDBCConnection();
+
 
         // steps:
         // 1) create a program entry in the reasoner_programs table
@@ -316,6 +327,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public void updateProgram(Program program) throws SQLException {
+        requireJDBCConnection();
+
         // steps:
         // 1) load old program by name
         // 2) create a diff between old and new program as follows:
@@ -435,6 +448,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException in case of a database problem or an unparsable program
      */
     public Program loadProgram(String name) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement loadProgram = getPreparedStatement("programs.load_by_name");
         synchronized (loadProgram) {
             loadProgram.setString(1, name);
@@ -462,6 +477,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public Program loadProgram(Long id) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement loadProgram = getPreparedStatement("programs.load_by_id");
         synchronized (loadProgram) {
             loadProgram.setLong(1, id);
@@ -519,6 +536,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public CloseableIteration<Program, SQLException> listPrograms() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement listPrograms = getPreparedStatement("programs.list");
         synchronized (listPrograms) {
             ResultSet result = listPrograms.executeQuery();
@@ -550,6 +569,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         // 1. delete all rule associations and rules including the justifications they depend on
         PreparedStatement deleteProgramRule = getPreparedStatement("programs.delete_rule");
         PreparedStatement deleteRule        = getPreparedStatement("rules.delete_by_id");
@@ -600,6 +621,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public void storeJustifications(Iterable<Justification> justifications) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement insertJustification = getPreparedStatement("justifications.insert");
         PreparedStatement justificationAddTriple = getPreparedStatement("justifications.add_triple");
         PreparedStatement justificationAddRule   = getPreparedStatement("justifications.add_rule");
@@ -675,6 +698,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public void deleteJustifications(Iteration<Justification, SQLException> justifications) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement deleteJustification = getPreparedStatement("justifications.delete");
         PreparedStatement deleteJustificationRules = getPreparedStatement("justifications.del_rule");
         PreparedStatement deleteJustificationTriples = getPreparedStatement("justifications.del_triple");
@@ -736,6 +761,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public void deleteJustifications() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement deleteJustification = getPreparedStatement("justifications.delete_all");
         PreparedStatement deleteJustificationRules = getPreparedStatement("justifications.delete_all_rules");
         PreparedStatement deleteJustificationTriples = getPreparedStatement("justifications.delete_all_triples");
@@ -757,6 +784,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
         if(rule.getId() == null) {
             return new EmptyIteration<Justification, SQLException>();
         } else {
+            requireJDBCConnection();
+
             PreparedStatement listByRule = getPreparedStatement("justifications.load_by_srule");
             synchronized (listByRule) {
                 listByRule.setLong(1, rule.getId());
@@ -783,6 +812,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
         if(triple.getId() == null) {
             return new EmptyIteration<Justification, SQLException>();
         } else {
+            requireJDBCConnection();
+
             PreparedStatement listByTriple = getPreparedStatement("justifications.load_by_striple");
             synchronized (listByTriple) {
                 listByTriple.setLong(1, triple.getId());
@@ -820,6 +851,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public CloseableIteration<Justification,SQLException> listJustificationsForTriple(long tripleId) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement listForTriple = getPreparedStatement("justifications.load_by_triple");
         synchronized (listForTriple) {
             listForTriple.setLong(1, tripleId);
@@ -872,6 +905,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public CloseableIteration<KiWiTriple, SQLException> listUnsupportedTriples() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement listUnsupported = getPreparedStatement("justifications.list_unsupported");
         synchronized (listUnsupported) {
             ResultSet result = listUnsupported.executeQuery();
@@ -913,6 +948,8 @@ public class KiWiReasoningConnection extends KiWiConnection {
      *         variables and offset and limited by the parameters given
      */
     public CloseableIteration<QueryResult, SQLException> query(final Collection<Pattern> patterns, final QueryResult initialBindings, Set<Filter> filters, List<VariableField> orderBy, final boolean justifications) throws SQLException {
+        requireJDBCConnection();
+
         if(filters != null) {
             throw new IllegalArgumentException("filters are not yet supported by the QueryService");
         }

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningPersistence.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningPersistence.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningPersistence.java
index e6fccc0..db1bb7a 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningPersistence.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/persistence/KiWiReasoningPersistence.java
@@ -90,7 +90,7 @@ public class KiWiReasoningPersistence {
      * @throws java.sql.SQLException in case a new connection could not be established
      */
     public KiWiReasoningConnection getConnection() throws SQLException {
-        return new KiWiReasoningConnection(persistence.getJDBCConnection(), persistence.getDialect(), persistence.getCacheManager(), valueFactory );
+        return new KiWiReasoningConnection(persistence, persistence.getDialect(), persistence.getCacheManager(), valueFactory );
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/model/collection/WeakValueMap.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/model/collection/WeakValueMap.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/model/collection/WeakValueMap.java
deleted file mode 100644
index c85969d..0000000
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/model/collection/WeakValueMap.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.marmotta.kiwi.model.collection;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableSet;
-
-import java.lang.ref.WeakReference;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * An implementation of a hash map with weak values (similar to the Java WeakHashMap, which uses weak keys).
- * <p/>
- * Author: Sebastian Schaffert
- */
-public class WeakValueMap<K,V> implements Map<K,V> {
-
-
-    private HashMap<K,WeakReference<V>> delegate;
-
-
-    public WeakValueMap() {
-        delegate = new HashMap<K, WeakReference<V>>();
-    }
-
-
-    public WeakValueMap(int initialCapacity) {
-        delegate = new HashMap<K, WeakReference<V>>(initialCapacity);
-    }
-
-
-    /**
-     * Removes all of the mappings from this map (optional operation).
-     * The map will be empty after this call returns.
-     *
-     * @throws UnsupportedOperationException if the <tt>clear</tt> operation
-     *                                       is not supported by this map
-     */
-    @Override
-    public void clear() {
-        delegate.clear();
-    }
-
-    /**
-     * Returns the number of key-value mappings in this map.  If the
-     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
-     *
-     * @return the number of key-value mappings in this map
-     */
-    @Override
-    public int size() {
-        return delegate.size();
-    }
-
-    /**
-     * Returns <tt>true</tt> if this map contains no key-value mappings.
-     *
-     * @return <tt>true</tt> if this map contains no key-value mappings
-     */
-    @Override
-    public boolean isEmpty() {
-        return delegate.isEmpty();
-    }
-
-
-    /**
-     * Returns <tt>true</tt> if this map contains a mapping for the specified
-     * key.  More formally, returns <tt>true</tt> if and only if
-     * this map contains a mapping for a key <tt>k</tt> such that
-     * <tt>(key==null ? k==null : key.equals(k))</tt>.  (There can be
-     * at most one such mapping.)
-     *
-     * @param key key whose presence in this map is to be tested
-     * @return <tt>true</tt> if this map contains a mapping for the specified
-     *         key
-     * @throws ClassCastException   if the key is of an inappropriate type for
-     *                              this map
-     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws NullPointerException if the specified key is null and this map
-     *                              does not permit null keys
-     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
-     */
-    @Override
-    public boolean containsKey(Object key) {
-        return delegate.containsKey(key);
-    }
-
-    /**
-     * Returns <tt>true</tt> if this map maps one or more keys to the
-     * specified value.  More formally, returns <tt>true</tt> if and only if
-     * this map contains at least one mapping to a value <tt>v</tt> such that
-     * <tt>(value==null ? v==null : value.equals(v))</tt>.  This operation
-     * will probably require time linear in the map size for most
-     * implementations of the <tt>Map</tt> interface.
-     *
-     * @param value value whose presence in this map is to be tested
-     * @return <tt>true</tt> if this map maps one or more keys to the
-     *         specified value
-     * @throws ClassCastException   if the value is of an inappropriate type for
-     *                              this map
-     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws NullPointerException if the specified value is null and this
-     *                              map does not permit null values
-     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
-     */
-	@Override
-	@SuppressWarnings("unchecked")
-    public boolean containsValue(Object value) {
-        try {
-            return delegate.containsValue(new WeakReference<V>((V)value));
-        } catch(ClassCastException ex) {
-            return false;
-        }
-    }
-
-    /**
-     * Returns the value to which the specified key is mapped,
-     * or {@code null} if this map contains no mapping for the key.
-     * <p/>
-     * <p>More formally, if this map contains a mapping from a key
-     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
-     * key.equals(k))}, then this method returns {@code v}; otherwise
-     * it returns {@code null}.  (There can be at most one such mapping.)
-     * <p/>
-     * <p>If this map permits null values, then a return value of
-     * {@code null} does not <i>necessarily</i> indicate that the map
-     * contains no mapping for the key; it's also possible that the map
-     * explicitly maps the key to {@code null}.  The {@link #containsKey
-     * containsKey} operation may be used to distinguish these two cases.
-     *
-     * @param key the key whose associated value is to be returned
-     * @return the value to which the specified key is mapped, or
-     *         {@code null} if this map contains no mapping for the key
-     * @throws ClassCastException   if the key is of an inappropriate type for
-     *                              this map
-     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws NullPointerException if the specified key is null and this map
-     *                              does not permit null keys
-     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
-     */
-    @Override
-    public V get(Object key) {
-        WeakReference<V> ref = delegate.get(key);
-        if(ref != null) {
-            return ref.get();
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Associates the specified value with the specified key in this map
-     * (optional operation).  If the map previously contained a mapping for
-     * the key, the old value is replaced by the specified value.  (A map
-     * <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only
-     * if {@link #containsKey(Object) m.containsKey(k)} would return
-     * <tt>true</tt>.)
-     *
-     * @param key   key with which the specified value is to be associated
-     * @param value value to be associated with the specified key
-     * @return the previous value associated with <tt>key</tt>, or
-     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
-     *         (A <tt>null</tt> return can also indicate that the map
-     *         previously associated <tt>null</tt> with <tt>key</tt>,
-     *         if the implementation supports <tt>null</tt> values.)
-     * @throws UnsupportedOperationException if the <tt>put</tt> operation
-     *                                       is not supported by this map
-     * @throws ClassCastException            if the class of the specified key or value
-     *                                       prevents it from being stored in this map
-     * @throws NullPointerException          if the specified key or value is null
-     *                                       and this map does not permit null keys or values
-     * @throws IllegalArgumentException      if some property of the specified key
-     *                                       or value prevents it from being stored in this map
-     */
-    @Override
-    public V put(K key, V value) {
-        WeakReference<V> prev = delegate.put(key,new WeakReference<V>(value));
-
-        if(prev != null) {
-            return prev.get();
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Removes the mapping for a key from this map if it is present
-     * (optional operation).   More formally, if this map contains a mapping
-     * from key <tt>k</tt> to value <tt>v</tt> such that
-     * <code>(key==null ?  k==null : key.equals(k))</code>, that mapping
-     * is removed.  (The map can contain at most one such mapping.)
-     * <p/>
-     * <p>Returns the value to which this map previously associated the key,
-     * or <tt>null</tt> if the map contained no mapping for the key.
-     * <p/>
-     * <p>If this map permits null values, then a return value of
-     * <tt>null</tt> does not <i>necessarily</i> indicate that the map
-     * contained no mapping for the key; it's also possible that the map
-     * explicitly mapped the key to <tt>null</tt>.
-     * <p/>
-     * <p>The map will not contain a mapping for the specified key once the
-     * call returns.
-     *
-     * @param key key whose mapping is to be removed from the map
-     * @return the previous value associated with <tt>key</tt>, or
-     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
-     *                                       is not supported by this map
-     * @throws ClassCastException            if the key is of an inappropriate type for
-     *                                       this map
-     *                                       (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws NullPointerException          if the specified key is null and this
-     *                                       map does not permit null keys
-     *                                       (<a href="Collection.html#optional-restrictions">optional</a>)
-     */
-    @Override
-    public V remove(Object key) {
-        WeakReference<V> ref = delegate.remove(key);
-        if(ref != null) {
-            return ref.get();
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Copies all of the mappings from the specified map to this map
-     * (optional operation).  The effect of this call is equivalent to that
-     * of calling {@link #put(Object, Object) put(k, v)} on this map once
-     * for each mapping from key <tt>k</tt> to value <tt>v</tt> in the
-     * specified map.  The behavior of this operation is undefined if the
-     * specified map is modified while the operation is in progress.
-     *
-     * @param m mappings to be stored in this map
-     * @throws UnsupportedOperationException if the <tt>putAll</tt> operation
-     *                                       is not supported by this map
-     * @throws ClassCastException            if the class of a key or value in the
-     *                                       specified map prevents it from being stored in this map
-     * @throws NullPointerException          if the specified map is null, or if
-     *                                       this map does not permit null keys or values, and the
-     *                                       specified map contains null keys or values
-     * @throws IllegalArgumentException      if some property of a key or value in
-     *                                       the specified map prevents it from being stored in this map
-     */
-    @Override
-    public void putAll(Map<? extends K, ? extends V> m) {
-        for(Entry<? extends  K,? extends V> entry : m.entrySet()) {
-            delegate.put(entry.getKey(),new WeakReference<V>(entry.getValue()));
-        }
-    }
-
-    /**
-     * Returns a {@link java.util.Set} view of the keys contained in this map.
-     * The set is backed by the map, so changes to the map are
-     * reflected in the set, and vice-versa.  If the map is modified
-     * while an iteration over the set is in progress (except through
-     * the iterator's own <tt>remove</tt> operation), the results of
-     * the iteration are undefined.  The set supports element removal,
-     * which removes the corresponding mapping from the map, via the
-     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
-     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
-     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
-     * operations.
-     *
-     * @return a set view of the keys contained in this map
-     */
-    @Override
-    public Set<K> keySet() {
-        return delegate.keySet();
-    }
-
-    /**
-     * Returns a {@link java.util.Collection} view of the values contained in this map.
-     * The collection is backed by the map, so changes to the map are
-     * reflected in the collection, and vice-versa.  If the map is
-     * modified while an iteration over the collection is in progress
-     * (except through the iterator's own <tt>remove</tt> operation),
-     * the results of the iteration are undefined.  The collection
-     * supports element removal, which removes the corresponding
-     * mapping from the map, via the <tt>Iterator.remove</tt>,
-     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
-     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
-     * support the <tt>add</tt> or <tt>addAll</tt> operations.
-     *
-     * @return a collection view of the values contained in this map
-     */
-    @Override
-    public Collection<V> values() {
-        return Collections2.transform(delegate.values(), new Function<WeakReference<V>, V>() {
-            @Override
-            public V apply(WeakReference<V> input) {
-                return input.get();
-            }
-        });
-    }
-
-    /**
-     * Returns a {@link java.util.Set} view of the mappings contained in this map.
-     * The set is backed by the map, so changes to the map are
-     * reflected in the set, and vice-versa.  If the map is modified
-     * while an iteration over the set is in progress (except through
-     * the iterator's own <tt>remove</tt> operation, or through the
-     * <tt>setValue</tt> operation on a map entry returned by the
-     * iterator) the results of the iteration are undefined.  The set
-     * supports element removal, which removes the corresponding
-     * mapping from the map, via the <tt>Iterator.remove</tt>,
-     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
-     * <tt>clear</tt> operations.  It does not support the
-     * <tt>add</tt> or <tt>addAll</tt> operations.
-     *
-     * @return a set view of the mappings contained in this map
-     */
-    @Override
-    public Set<Entry<K, V>> entrySet() {
-        return ImmutableSet.copyOf(Collections2.transform(delegate.entrySet(), new Function<Entry<K, WeakReference<V>>, Entry<K, V>>() {
-            @Override
-            public Entry<K, V> apply(final Entry<K, WeakReference<V>> input) {
-                return new Entry<K,V>() {
-                    @Override
-                    public K getKey() {
-                        return input.getKey();
-                    }
-
-                    @Override
-                    public V getValue() {
-                        return input.getValue().get();
-                    }
-
-                     @Override
-                    public V setValue(V value) {
-                        return input.setValue(new WeakReference<V>(value)).get();
-                    }
-                };
-            }
-        }));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java
index c8e27d0..e582631 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java
+++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java
@@ -66,6 +66,7 @@ public class KiWiConnection {
 
     protected Connection connection;
 
+    protected KiWiPersistence  persistence;
 
     protected KiWiCacheManager cacheManager;
 
@@ -116,11 +117,13 @@ public class KiWiConnection {
 
     private Map<String,PreparedStatement> statementCache;
 
+    private boolean autoCommit = false;
 
-    public KiWiConnection(Connection connection, KiWiDialect dialect, KiWiCacheManager cacheManager) throws SQLException {
+
+    public KiWiConnection(KiWiPersistence persistence, KiWiDialect dialect, KiWiCacheManager cacheManager) throws SQLException {
         this.cacheManager = cacheManager;
-        this.connection = connection;
-        this.dialect = dialect;
+        this.dialect      = dialect;
+        this.persistence  = persistence;
 
         initCachePool();
         initStatementCache();
@@ -151,6 +154,16 @@ public class KiWiConnection {
         */
     }
 
+    /**
+     * This method must be called by all methods as soon as they actually require a JDBC connection. This allows
+     * more efficient implementations in case the queries can be answered directly from the cache.
+     */
+    protected void requireJDBCConnection() throws SQLException {
+        if(connection == null) {
+            connection = persistence.getJDBCConnection();
+            connection.setAutoCommit(autoCommit);
+        }
+    }
 
     /**
      * Get direct access to the JDBC connection used by this KiWiConnection.
@@ -184,6 +197,8 @@ public class KiWiConnection {
             return (KiWiNamespace)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // prepare a query; we will only iterate once, read only, and need only one result row since the id is unique
         PreparedStatement query = getPreparedStatement("load.namespace_prefix");
         query.setString(1, prefix);
@@ -218,6 +233,8 @@ public class KiWiConnection {
             return (KiWiNamespace)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // prepare a query; we will only iterate once, read only, and need only one result row since the id is unique
         PreparedStatement query = getPreparedStatement("load.namespace_uri");
         query.setString(1, uri);
@@ -251,6 +268,8 @@ public class KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         namespace.setId(getNextSequence("seq.namespaces"));
 
         PreparedStatement insertNamespace = getPreparedStatement("store.namespace");
@@ -276,6 +295,8 @@ public class KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         PreparedStatement deleteNamespace = getPreparedStatement("delete.namespace");
         deleteNamespace.setLong(1, namespace.getId());
         deleteNamespace.executeUpdate();
@@ -290,6 +311,8 @@ public class KiWiConnection {
      * @throws SQLException
      */
     public long getSize() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement querySize = getPreparedStatement("query.size");
         ResultSet result = querySize.executeQuery();
         try {
@@ -312,6 +335,9 @@ public class KiWiConnection {
         if(context.getId() == null) {
             return 0;
         };
+
+        requireJDBCConnection();
+
         PreparedStatement querySize = getPreparedStatement("query.size_ctx");
         querySize.setLong(1,context.getId());
 
@@ -361,6 +387,8 @@ public class KiWiConnection {
             return (KiWiNode)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // prepare a query; we will only iterate once, read only, and need only one result row since the id is unique
         PreparedStatement query = getPreparedStatement("load.node_by_id");
         query.setLong(1,id);
@@ -389,6 +417,8 @@ public class KiWiConnection {
             return (KiWiTriple)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // prepare a query; we will only iterate once, read only, and need only one result row since the id is unique
         PreparedStatement query = getPreparedStatement("load.triple_by_id");
         query.setLong(1,id);
@@ -427,6 +457,8 @@ public class KiWiConnection {
             return (KiWiUriResource)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // prepare a query; we will only iterate once, read only, and need only one result row since the id is unique
         PreparedStatement query = getPreparedStatement("load.uri_by_uri");
         query.setString(1, uri);
@@ -466,6 +498,8 @@ public class KiWiConnection {
             return (KiWiAnonResource)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // prepare a query; we will only iterate once, read only, and need only one result row since the id is unique
         PreparedStatement query = getPreparedStatement("load.bnode_by_anonid");
         query.setString(1,id);
@@ -512,6 +546,8 @@ public class KiWiConnection {
             return null;
         }
 
+        requireJDBCConnection();
+
         // otherwise prepare a query, depending on the parameters given
         final PreparedStatement query;
         if(lang == null && ltype == null) {
@@ -570,6 +606,8 @@ public class KiWiConnection {
             return (KiWiDateLiteral)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // otherwise prepare a query, depending on the parameters given
         PreparedStatement query = getPreparedStatement("load.literal_by_tv");
         query.setTimestamp(1, new Timestamp(DateUtils.getDateWithoutFraction(date).getTime()));
@@ -617,6 +655,8 @@ public class KiWiConnection {
             return (KiWiIntLiteral)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // otherwise prepare a query, depending on the parameters given
         PreparedStatement query = getPreparedStatement("load.literal_by_iv");
         query.setLong(1,value);
@@ -663,6 +703,8 @@ public class KiWiConnection {
             return (KiWiDoubleLiteral)element.getObjectValue();
         }
 
+        requireJDBCConnection();
+
         // otherwise prepare a query, depending on the parameters given
         PreparedStatement query = getPreparedStatement("load.literal_by_dv");
         query.setDouble(1, value);
@@ -710,6 +752,8 @@ public class KiWiConnection {
         }
 
 
+        requireJDBCConnection();
+
         // otherwise prepare a query, depending on the parameters given
         PreparedStatement query = getPreparedStatement("load.literal_by_bv");
         query.setBoolean(1, value);
@@ -760,6 +804,8 @@ public class KiWiConnection {
             }
         }
 
+        requireJDBCConnection();
+
         // retrieve a new node id and set it in the node object
         node.setId(getNextSequence("seq.nodes"));
 
@@ -884,6 +930,8 @@ public class KiWiConnection {
         Preconditions.checkNotNull(triple.getContext().getId());
 
 
+        requireJDBCConnection();
+
         // retrieve a new triple ID and set it in the object
         triple.setId(getNextSequence("seq.triples"));
 
@@ -916,6 +964,8 @@ public class KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         PreparedStatement deleteTriple = getPreparedStatement("delete.triple");
         deleteTriple.setLong(1,triple.getId());
         deleteTriple.executeUpdate();
@@ -928,6 +978,43 @@ public class KiWiConnection {
     }
 
     /**
+     * Mark the triple passed as argument as not deleted, setting the "deleted" flag to false and
+     * clearing the timestamp value of "deletedAt".
+     * <p/>
+     * Note that this operation should only be called if the triple was deleted before in the same
+     * transaction!
+     *
+     * @param triple
+     */
+    public void undeleteTriple(KiWiTriple triple) throws SQLException {
+        if(triple.getId() == null) {
+            log.warn("attempting to undelete non-persistent triple: {}",triple);
+            return;
+        }
+
+        requireJDBCConnection();
+
+        synchronized (triple) {
+            if(!triple.isDeleted()) {
+                log.warn("attemting to undelete triple that was not deleted: {}",triple);
+                return;
+            }
+
+            PreparedStatement undeleteTriple = getPreparedStatement("undelete.triple");
+            undeleteTriple.setLong(1, triple.getId());
+            undeleteTriple.executeUpdate();
+
+            // make sure the triple is marked as deleted in case some service still holds a reference
+            triple.setDeleted(false);
+            triple.setDeletedAt(null);
+
+            cacheTriple(triple);
+        }
+
+    }
+
+
+    /**
      * Remove from the database all triples that have been marked as deleted and are not referenced by any other
      * entity.
      */
@@ -942,6 +1029,8 @@ public class KiWiConnection {
      * @throws SQLException
      */
     public CloseableIteration<KiWiResource, SQLException> listContexts() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryContexts = getPreparedStatement("query.contexts");
 
         final ResultSet result = queryContexts.executeQuery();
@@ -957,6 +1046,8 @@ public class KiWiConnection {
 
 
     public CloseableIteration<KiWiNamespace, SQLException> listNamespaces() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryContexts = getPreparedStatement("query.namespaces");
 
         final ResultSet result = queryContexts.executeQuery();
@@ -1030,6 +1121,8 @@ public class KiWiConnection {
             return new EmptyIteration<Statement, SQLException>();
         }
 
+        requireJDBCConnection();
+
         // otherwise we need to create an appropriate SQL query and execute it, the repository result will be read-only
         // and only allow forward iteration, so we can limit the query using the respective flags
         PreparedStatement query = connection.prepareStatement(
@@ -1283,6 +1376,8 @@ public class KiWiConnection {
      * @throws SQLException
      */
     public PreparedStatement getPreparedStatement(String key) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement statement = statementCache.get(key);
         if(statement == null) {
             statement = connection.prepareStatement(dialect.getStatement(key));
@@ -1301,6 +1396,8 @@ public class KiWiConnection {
      * @throws SQLException
      */
     public long getNextSequence(String sequenceName) throws SQLException {
+        requireJDBCConnection();
+
         // retrieve a new node id and set it in the node object
 
         // if there is a preparation needed to update the transaction, run it first
@@ -1359,6 +1456,8 @@ public class KiWiConnection {
      * @throws SQLException
      */
     public Set<String> getDatabaseTables() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement statement = getPreparedStatement("meta.tables");
         ResultSet result = statement.executeQuery();
         try {
@@ -1380,6 +1479,8 @@ public class KiWiConnection {
      * @return
      */
     public int getDatabaseVersion() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement statement = getPreparedStatement("meta.version");
         ResultSet result = statement.executeQuery();
         try {
@@ -1430,7 +1531,10 @@ public class KiWiConnection {
      * @see #getAutoCommit
      */
     public void setAutoCommit(boolean autoCommit) throws SQLException {
-        connection.setAutoCommit(autoCommit);
+        this.autoCommit = autoCommit;
+        if(connection != null) {
+            connection.setAutoCommit(autoCommit);
+        }
     }
 
 
@@ -1445,7 +1549,7 @@ public class KiWiConnection {
      * @see #setAutoCommit
      */
     public boolean getAutoCommit() throws SQLException {
-        return connection.getAutoCommit();
+        return autoCommit;
     }
 
     /**
@@ -1462,7 +1566,9 @@ public class KiWiConnection {
      * @see #setAutoCommit
      */
     public void commit() throws SQLException {
-        connection.commit();
+        if(connection != null) {
+            connection.commit();
+        }
     }
 
     /**
@@ -1478,7 +1584,7 @@ public class KiWiConnection {
      * @see #setAutoCommit
      */
     public void rollback() throws SQLException {
-        if(!connection.isClosed()) {
+        if(connection != null && !connection.isClosed()) {
             connection.rollback();
         }
     }
@@ -1501,7 +1607,11 @@ public class KiWiConnection {
      * @exception java.sql.SQLException if a database access error occurs
      */
     public boolean isClosed() throws SQLException {
-        return connection.isClosed();
+        if(connection != null) {
+            return connection.isClosed();
+        } else {
+            return false;
+        }
     }
 
 
@@ -1521,17 +1631,19 @@ public class KiWiConnection {
      * @exception java.sql.SQLException SQLException if a database access error occurs
      */
     public void close() throws SQLException {
-        // close all prepared statements
-        try {
-            for(Map.Entry<String,PreparedStatement> entry : statementCache.entrySet()) {
-                try {
-                    entry.getValue().close();
-                } catch (SQLException ex) {}
+        if(connection != null) {
+            // close all prepared statements
+            try {
+                for(Map.Entry<String,PreparedStatement> entry : statementCache.entrySet()) {
+                    try {
+                        entry.getValue().close();
+                    } catch (SQLException ex) {}
+                }
+            } catch(AbstractMethodError ex) {
+                log.debug("database system does not allow closing statements");
             }
-        } catch(AbstractMethodError ex) {
-            log.debug("database system does not allow closing statements");
-        }
 
-        connection.close();
+            connection.close();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/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 399b4eb..bb8604d 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
@@ -291,13 +291,7 @@ public class KiWiPersistence {
      * @throws SQLException in case a new connection could not be established
      */
     public KiWiConnection getConnection() throws SQLException {
-        Connection conn = connectionPool.getConnection();
-        conn.setAutoCommit(false);
-        //conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
-
-        //managedConnections.add(conn);
-
-        return new KiWiConnection(conn,dialect,cacheManager);
+        return new KiWiConnection(this,dialect,cacheManager);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/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 9ba9399..d4c84b3 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
@@ -89,6 +89,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
 
     private boolean triplesAdded, triplesRemoved;
 
+    private HashSet<Long> deletedStatementsLog;
 
     public KiWiSailConnection(KiWiStore sailBase) throws SailException {
         super(sailBase);
@@ -160,13 +161,21 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
             for(Resource context : contextSet) {
                 KiWiResource kcontext = valueFactory.convert(context);
 
-                KiWiTriple triple = (KiWiTriple)valueFactory.createStatement(ksubj,kpred,kobj,kcontext);
+                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);
+                    triplesAdded = true;
+                    notifyStatementAdded(triple);
                 }
 
                 added.add(triple);
@@ -334,6 +343,7 @@ 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
@@ -344,6 +354,8 @@ 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
                 public Sail getSail() {
@@ -367,6 +379,7 @@ 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);
         }
@@ -381,6 +394,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
                 if(triple.getId() != null) {
                     databaseConnection.deleteTriple(triple);
                     triplesRemoved = true;
+                    deletedStatementsLog.add(triple.getId());
                     notifyStatementRemoved(triple);
                 }
             }
@@ -411,6 +425,7 @@ public class KiWiSailConnection extends NotifyingSailConnectionBase implements I
                 if(triple.getId() != null && triple.isInferred()) {
                     databaseConnection.deleteTriple(triple);
                     triplesRemoved = true;
+                    deletedStatementsLog.add(triple.getId());
                     notifyStatementRemoved(triple);
                 }
             }
@@ -438,6 +453,7 @@ 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) {

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/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 d07bd8a..3c71e2c 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
@@ -19,11 +19,6 @@ package org.apache.marmotta.kiwi.sail;
 
 import com.google.common.collect.MapMaker;
 import org.apache.marmotta.kiwi.model.caching.IntArray;
-import org.apache.marmotta.kiwi.model.collection.WeakValueMap;
-import org.apache.marmotta.kiwi.model.rdf.KiWiAnonResource;
-import org.apache.marmotta.kiwi.model.rdf.KiWiLiteral;
-import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
-import org.apache.marmotta.kiwi.persistence.KiWiConnection;
 import org.apache.marmotta.kiwi.persistence.KiWiDialect;
 import org.apache.marmotta.kiwi.persistence.KiWiPersistence;
 import org.openrdf.model.Statement;

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/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 3c948a0..22038f6 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
@@ -18,12 +18,11 @@
 package org.apache.marmotta.kiwi.sail;
 
 import com.google.common.collect.MapMaker;
+import org.apache.commons.lang.LocaleUtils;
 import org.apache.marmotta.commons.sesame.model.LiteralCommons;
 import org.apache.marmotta.commons.sesame.model.Namespaces;
 import org.apache.marmotta.commons.util.DateUtils;
-import org.apache.commons.lang.LocaleUtils;
 import org.apache.marmotta.kiwi.model.caching.IntArray;
-import org.apache.marmotta.kiwi.model.collection.WeakValueMap;
 import org.apache.marmotta.kiwi.model.rdf.*;
 import org.apache.marmotta.kiwi.persistence.KiWiConnection;
 import org.openrdf.model.BNode;
@@ -33,6 +32,8 @@ import org.openrdf.model.Statement;
 import org.openrdf.model.URI;
 import org.openrdf.model.Value;
 import org.openrdf.model.ValueFactory;
+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;
@@ -546,6 +547,8 @@ 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 {
@@ -579,8 +582,52 @@ public class KiWiValueFactory implements ValueFactory {
             releaseConnection(connection);
             tripleLock.unlock();
         }
+        */
     }
 
+    /**
+     * Creates a new statement with the supplied subject, predicate and object and associated context. This is a
+     * specialised form of createStatement that allows the existance check for a triple to run in the same connection
+     * as the rest of the repository operations.
+     *
+     * @param subject   The statement's subject.
+     * @param predicate The statement's predicate.
+     * @param object    The statement's object.
+     * @param context   The statement's context.
+     * @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);
+        try {
+            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);
+        }
+    }
+
+
 
     public KiWiResource convert(Resource r) {
         return (KiWiResource)convert((Value)r);

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/statements.properties
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/statements.properties b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/statements.properties
index 42a67ea..2fc9afc 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/statements.properties
+++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/h2/statements.properties
@@ -71,4 +71,5 @@ query.namespaces     = SELECT id,prefix,uri,createdAt FROM namespaces
 
 # delete entities
 delete.triple        = UPDATE triples SET deleted = true, deletedAt = now() WHERE id = ?
+undelete.triple      = UPDATE triples SET deleted = false, deletedAt = NULL WHERE id = ?
 delete.namespace     = DELETE FROM namespaces WHERE id = ?

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
index 9fe6a82..fae51bc 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
+++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
@@ -75,4 +75,5 @@ query.namespaces     = SELECT id,prefix,uri,createdAt FROM namespaces
 
 # delete entities
 delete.triple        = UPDATE triples SET deleted = true, deletedAt = now() WHERE id = ?
+undelete.triple      = UPDATE triples SET deleted = false, deletedAt = NULL WHERE id = ?
 delete.namespace     = DELETE FROM namespaces WHERE id = ?

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
index f0d0e90..2b2f0c6 100644
--- a/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
+++ b/libraries/kiwi/kiwi-triplestore/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
@@ -67,4 +67,5 @@ query.namespaces     = SELECT id,prefix,uri,createdAt FROM namespaces
 
 # delete entities
 delete.triple        = UPDATE triples SET deleted = true, deletedAt = now() WHERE id = ?
+undelete.triple      = UPDATE triples SET deleted = false, deletedAt = NULL WHERE id = ?
 delete.namespace     = DELETE FROM namespaces WHERE id = ?

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-triplestore/src/test/java/org/apache/marmotta/kiwi/test/RepositoryTest.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-triplestore/src/test/java/org/apache/marmotta/kiwi/test/RepositoryTest.java b/libraries/kiwi/kiwi-triplestore/src/test/java/org/apache/marmotta/kiwi/test/RepositoryTest.java
index 6ff74ff..ff914e8 100644
--- a/libraries/kiwi/kiwi-triplestore/src/test/java/org/apache/marmotta/kiwi/test/RepositoryTest.java
+++ b/libraries/kiwi/kiwi-triplestore/src/test/java/org/apache/marmotta/kiwi/test/RepositoryTest.java
@@ -475,4 +475,60 @@ public class RepositoryTest {
 
 
     }
+
+    /**
+     * Test adding-deleting-adding a triple
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testRepeatedAddRemoveTransaction() throws Exception {
+        String value = RandomStringUtils.randomAlphanumeric(8);
+
+        URI subject = repository.getValueFactory().createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8));
+        URI predicate = repository.getValueFactory().createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8));
+        Literal object1 = repository.getValueFactory().createLiteral(value);
+
+        RepositoryConnection connection1 = repository.getConnection();
+        try {
+            connection1.add(subject,predicate,object1);
+            connection1.commit();
+
+            Assert.assertTrue(connection1.hasStatement(subject,predicate,object1,true));
+
+            connection1.commit();
+        } finally {
+            connection1.close();
+        }
+
+        Literal object2 = repository.getValueFactory().createLiteral(value);
+        Literal object3 = repository.getValueFactory().createLiteral(value);
+        RepositoryConnection connection2 = repository.getConnection();
+        try {
+            Assert.assertTrue(connection2.hasStatement(subject,predicate,object2,true));
+
+            connection2.remove(subject,predicate,object2);
+            Assert.assertFalse(connection2.hasStatement(subject,predicate,object2,true));
+
+            connection2.add(subject,predicate,object3);
+            Assert.assertTrue(connection2.hasStatement(subject,predicate,object3,true));
+
+            connection2.commit();
+        } finally {
+            connection2.close();
+        }
+
+        Literal object4 = repository.getValueFactory().createLiteral(value);
+        RepositoryConnection connection4 = repository.getConnection();
+        try {
+            Assert.assertTrue(connection4.hasStatement(subject,predicate,object4,true));
+
+            connection4.commit();
+        } finally {
+            connection4.close();
+        }
+
+
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java b/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
index 0ae8118..054cf20 100644
--- a/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
+++ b/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
@@ -27,6 +27,7 @@ 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.apache.marmotta.kiwi.persistence.KiWiDialect;
+import org.apache.marmotta.kiwi.persistence.KiWiPersistence;
 import org.apache.marmotta.kiwi.persistence.util.ResultSetIteration;
 import org.apache.marmotta.kiwi.persistence.util.ResultTransformerFunction;
 import org.apache.marmotta.kiwi.versioning.model.Version;
@@ -52,8 +53,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
 
     private static Logger log = LoggerFactory.getLogger(KiWiVersioningConnection.class);
 
-    public KiWiVersioningConnection(Connection connection, KiWiDialect dialect, KiWiCacheManager cacheManager) throws SQLException {
-        super(connection, dialect, cacheManager);
+    public KiWiVersioningConnection(KiWiPersistence persistence, KiWiDialect dialect, KiWiCacheManager cacheManager) throws SQLException {
+        super(persistence, dialect, cacheManager);
     }
 
 
@@ -75,6 +76,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
             return;
         }
 
+        requireJDBCConnection();
+
         // first create a new entry in the version table
         data.setId(getNextSequence("seq.versions"));
 
@@ -134,6 +137,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public Version getVersion(Long id) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryVersions = getPreparedStatement("load.version_by_id");
         queryVersions.setLong(1,id);
         queryVersions.setMaxRows(1);
@@ -161,6 +166,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
      * @throws SQLException
      */
     public Version getLatestVersion(KiWiResource resource, Date date) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryVersions = getPreparedStatement("load.versions_by_resource_latest");
         synchronized (queryVersions) {
             queryVersions.setLong(1, resource.getId());
@@ -210,6 +217,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
      * @throws SQLException
      */
     private CloseableIteration<Version, SQLException> listVersionsInternal() throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryVersions = getPreparedStatement("load.versions");
 
         final ResultSet result = queryVersions.executeQuery();
@@ -253,6 +262,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
         if(r.getId() == null) {
             return new EmptyIteration<Version, SQLException>();
         } else {
+            requireJDBCConnection();
+
             PreparedStatement queryVersions = getPreparedStatement("load.versions_by_resource");
             queryVersions.setLong(1,r.getId());
 
@@ -297,6 +308,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
      * @throws SQLException
      */
     private CloseableIteration<Version, SQLException> listVersionsInternal(Date from, Date to) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryVersions = getPreparedStatement("load.version_between");
         synchronized (queryVersions) {
             queryVersions.clearParameters();
@@ -343,6 +356,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
      * @throws SQLException
      */
     private CloseableIteration<Version, SQLException> listVersionsInternal(KiWiResource r, Date from, Date to) throws SQLException {
+        requireJDBCConnection();
+
         PreparedStatement queryVersions = getPreparedStatement("load.versions_by_resource_between");
         synchronized (queryVersions) {
             queryVersions.clearParameters();
@@ -477,6 +492,8 @@ public class KiWiVersioningConnection extends KiWiConnection {
             return new EmptyIteration<Statement, SQLException>();
         }
 
+        requireJDBCConnection();
+
         // otherwise we need to create an appropriate SQL query and execute it, the repository result will be read-only
         // and only allow forward iteration, so we can limit the query using the respective flags
         PreparedStatement query = connection.prepareStatement(
@@ -578,6 +595,9 @@ public class KiWiVersioningConnection extends KiWiConnection {
         if(context.getId() == null) {
             return 0;
         };
+
+        requireJDBCConnection();
+
         PreparedStatement querySize = getPreparedStatement("query.snapshot_size_ctx");
         querySize.setLong(1,context.getId());
         querySize.setTimestamp(2, new Timestamp(snapshotDate.getTime()));

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c4ca14f0/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java b/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
index 82a026b..797c58c 100644
--- a/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
+++ b/libraries/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
@@ -77,7 +77,7 @@ public class KiWiVersioningPersistence {
      * @throws java.sql.SQLException in case a new connection could not be established
      */
     public KiWiVersioningConnection getConnection() throws SQLException {
-        return new KiWiVersioningConnection(persistence.getJDBCConnection(), persistence.getDialect(), persistence.getCacheManager());
+        return new KiWiVersioningConnection(persistence, persistence.getDialect(), persistence.getCacheManager());
     }