jena-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a...@apache.org
Subject [1/8] jena git commit: JENA-1481, JENA-1586: Delete databases and expel from JVM
Date Sun, 12 Aug 2018 09:53:51 GMT
Repository: jena
Updated Branches:
  refs/heads/master 85a5a3b4e -> a515c111b


JENA-1481, JENA-1586: Delete databases and expel from JVM


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/5a51311b
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/5a51311b
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/5a51311b

Branch: refs/heads/master
Commit: 5a51311bd5b4ab2daf2f9cb9bb8a42a9d372e325
Parents: 7b011c3
Author: Andy Seaborne <andy@apache.org>
Authored: Fri Aug 10 16:21:39 2018 +0100
Committer: Andy Seaborne <andy@apache.org>
Committed: Fri Aug 10 18:15:08 2018 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/jena/atlas/io/IO.java  |  32 ++++++
 .../org/apache/jena/tdb2/sys/TDBInternal.java   |  19 +++-
 .../java/org/apache/jena/fuseki/FusekiLib.java  |   6 +-
 .../jena/fuseki/build/FusekiBuildLib.java       |  14 +++
 .../apache/jena/fuseki/mgt/ActionDatasets.java  | 111 +++++++++++++++----
 .../src/main/webapp/WEB-INF/web.xml             |   5 -
 .../java/org/apache/jena/fuseki/TS_Fuseki.java  |   1 +
 .../java/org/apache/jena/fuseki/TestAdmin.java  |   1 -
 .../org/apache/jena/fuseki/TestAdminAPI.java    | 102 +++++++++++++++++
 .../org/apache/jena/tdb/sys/TDBInternal.java    |  10 ++
 10 files changed, 268 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java b/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
index 18b4df9..2c64cb5 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
@@ -21,6 +21,11 @@ package org.apache.jena.atlas.io;
 import java.io.* ;
 import java.nio.charset.Charset ;
 import java.nio.charset.StandardCharsets ;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.zip.GZIPInputStream ;
 import java.util.zip.GZIPOutputStream ;
 
@@ -364,4 +369,31 @@ public class IO
             return null ;
         }
     }
+    
+    /** Delete everything from a {@code Path} start point, including the path itself.
+     * This function works on files or directories.
+     * This function does not follow symbolic links.
+     */  
+    public static void deleteAll(Path start) {
+        // Walks down the tree and delete directories on the way backup.
+        try { 
+            Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws
IOException {
+                    Files.delete(file);
+                    return FileVisitResult.CONTINUE;
+                }
+                @Override
+                public FileVisitResult postVisitDirectory(Path dir, IOException e) throws
IOException {
+                    if (e == null) {
+                        Files.delete(dir);
+                        return FileVisitResult.CONTINUE;
+                    } else {
+                        throw e;
+                    }
+                }
+            });
+        }
+        catch (IOException ex) { IO.exception(ex) ; return; }
+    }
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/TDBInternal.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/TDBInternal.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/TDBInternal.java
index 56c3f40..c0832e3 100644
--- a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/TDBInternal.java
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/TDBInternal.java
@@ -160,7 +160,7 @@ public class TDBInternal {
         return null;
     }
 
-    /** Stop managing a DatasetGraph. Use with great care (testing only). */
+    /** Stop managing a DatasetGraph. Use with great care. */
     public static synchronized void expel(DatasetGraph dsg) {
         Location locContainer = null;
         Location locStorage = null;
@@ -176,6 +176,23 @@ public class TDBInternal {
         StoreConnection.internalExpel(locStorage, false);
     }
 
+    /** Stop managing a DatasetGraph. Use with great care. */
+    public static synchronized void expel(DatasetGraph dsg, boolean force) {
+        Location locContainer = null;
+        Location locStorage = null;
+        
+        if ( dsg instanceof DatasetGraphSwitchable ) {
+            locContainer = ((DatasetGraphSwitchable)dsg).getLocation();
+            dsg = ((DatasetGraphSwitchable)dsg).getWrapped();
+        }
+        if ( dsg instanceof DatasetGraphTDB )
+            locStorage = ((DatasetGraphTDB)dsg).getLocation();
+        
+        DatabaseConnection.internalExpel(locContainer, force);
+        StoreConnection.internalExpel(locStorage, force);
+    }
+
+    
     /** 
      * Reset the whole TDB system.      
      * Use with great care.

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
index 37162e8..e540a67 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
@@ -71,7 +71,7 @@ public class FusekiLib {
         return ContentType.create(contentTypeHeader) ;
     }
     
-    /** Get the incoming Lang based on Content-Type of an action.
+    /** Get the incoming {@link Lang} based on Content-Type of an action.
      * @param  action
      * @param  dft Default if no "Content-Type:" found. 
      * @return ContentType
@@ -178,8 +178,8 @@ public class FusekiLib {
     }
 
     /**
-     * Test whether a URL identifies a Fuseki server. This operation can not guaranttee to
-     * detech a Fuseki server - for example, it may be behind a reverse proxy that masks
+     * Test whether a URL identifies a Fuseki server. This operation can not guarantee to
+     * detect a Fuseki server - for example, it may be behind a reverse proxy that masks
      * the signature.
      */
     public static boolean isFuseki(String datasetURL) {

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuildLib.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuildLib.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuildLib.java
index 41bd8f4..e71edce 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuildLib.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuildLib.java
@@ -36,6 +36,20 @@ public class FusekiBuildLib {
         return query(string, m, null, null) ;
     }
 
+    public static RDFNode queryOne(String string, Model m, String varname) {
+        ResultSet rs = query(string, m) ;
+        return getExactlyOne(rs, varname);
+    }
+    
+    private static RDFNode getExactlyOne(ResultSet rs, String varname) {
+        if ( ! rs.hasNext() )
+            return null;
+        QuerySolution qs = rs.next();
+        if ( rs.hasNext() )
+            return null;
+        return qs.get(varname);
+    }
+
     public static ResultSet query(String string, Dataset ds) {
         return query(string, ds, null, null) ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
index 8ee6ff5..90a9852 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
@@ -20,15 +20,18 @@ package org.apache.jena.fuseki.mgt;
 
 import static java.lang.String.format ;
 
-import java.io.IOException ;
-import java.io.InputStream ;
-import java.io.OutputStream ;
-import java.io.StringReader ;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.*;
 
 import javax.servlet.http.HttpServletRequest ;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.jena.atlas.RuntimeIOException;
 import org.apache.jena.atlas.io.IO ;
 import org.apache.jena.atlas.json.JsonBuilder ;
 import org.apache.jena.atlas.json.JsonValue ;
@@ -38,12 +41,14 @@ import org.apache.jena.atlas.lib.StrUtils ;
 import org.apache.jena.atlas.web.ContentType ;
 import org.apache.jena.datatypes.xsd.XSDDatatype ;
 import org.apache.jena.fuseki.FusekiLib ;
-import org.apache.jena.fuseki.build.DatasetDescriptionRegistry ;
-import org.apache.jena.fuseki.build.FusekiBuilder ;
-import org.apache.jena.fuseki.build.Template ;
-import org.apache.jena.fuseki.build.TemplateFunctions ;
+import org.apache.jena.fuseki.build.DatasetDescriptionRegistry;
+import org.apache.jena.fuseki.build.FusekiBuilder;
+import org.apache.jena.fuseki.build.Template;
+import org.apache.jena.fuseki.build.TemplateFunctions;
 import org.apache.jena.fuseki.ctl.ActionContainerItem;
-import org.apache.jena.fuseki.server.* ;
+import org.apache.jena.fuseki.server.DataAccessPoint;
+import org.apache.jena.fuseki.server.DataService;
+import org.apache.jena.fuseki.server.FusekiVocab;
 import org.apache.jena.fuseki.servlets.ActionLib;
 import org.apache.jena.fuseki.servlets.HttpAction;
 import org.apache.jena.fuseki.servlets.ServletOps;
@@ -52,8 +57,9 @@ import org.apache.jena.fuseki.webapp.FusekiSystem;
 import org.apache.jena.fuseki.webapp.SystemState;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.graph.NodeFactory ;
-import org.apache.jena.query.Dataset ;
-import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.query.Dataset;
+import org.apache.jena.query.ReadWrite;
+import org.apache.jena.query.text.DatasetGraphText;
 import org.apache.jena.rdf.model.* ;
 import org.apache.jena.riot.* ;
 import org.apache.jena.riot.system.StreamRDF ;
@@ -228,7 +234,7 @@ public class ActionDatasets extends ActionContainerItem {
         }
         return null ;
     }
-    
+
     @Override
     protected JsonValue execPostItem(HttpAction action) {
         String name = action.getDatasetName() ;
@@ -288,28 +294,90 @@ public class ActionDatasets extends ActionContainerItem {
         if ( ! action.getDataAccessPointRegistry().isRegistered(name) )
             ServletOps.errorNotFound("No such dataset registered: "+name);
 
+        // This acts as a lock. 
         systemDSG.begin(ReadWrite.WRITE) ;
         boolean committed = false ;
+
         try {
             // Here, go offline.
             // Need to reference count operations when they drop to zero
             // or a timer goes off, we delete the dataset.
 
             DataAccessPoint ref = action.getDataAccessPointRegistry().get(name) ;
+            
             // Redo check inside transaction.
             if ( ref == null )
                 ServletOps.errorNotFound("No such dataset registered: "+name);
+            
+            String filename = name.startsWith("/") ? name.substring(1) : name;
+            List<String> configurationFiles = FusekiSystem.existingConfigurationFile(filename);
+            if  ( configurationFiles.size() != 1 ) {
+                // This should not happen.
+                action.log.warn(format("[%d] There are %d configuration files, not one.",
action.id, configurationFiles.size()));
+                ServletOps.errorOccurred(
+                    format(
+                        "There are %d configuration files, not one. Delete not performed;
clearup of the filesystem needed.",
+                        action.id, configurationFiles.size()));
+            }
+            
+            String cfgPathname = configurationFiles.get(0);
+            
+            // Delete configuration file.
+            // Once deleted, server restart will not have the database. 
+            FileOps.deleteSilent(cfgPathname);
 
-            // Make it invisible to the outside.
+            // Get before removing.
+            DatasetGraph database = ref.getDataService().getDataset();
+            // Make it invisible in this running server.
             action.getDataAccessPointRegistry().remove(name);
-            // Delete configuration file.
-            // Should be only one, undo damage if multiple.
-            String filename = name.startsWith("/") ? name.substring(1) : name;
-            FusekiSystem.existingConfigurationFile(filename).stream().forEach(FileOps::deleteSilent);
-            // Leave the database in place. if it is in /databases/, recreating the
-            // configuration will make the database reappear. This is intentional.
-            // Deleting a large database by accident is a major mistake.
 
+            // JENA-1481 & JENA-1586 : Delete the database.
+            // Delete the database for real only when it is in the server "run/databases"
+            // area. Don't delete databases that reside elsewhere. We do delete the
+            // configuration file, so the databases will not be associated with the server
+            // anymore.
+
+            boolean tryToRemoveFiles = true;
+            
+            // Text databases.
+            // Close the in-JVM objects for Lucene index and databases. 
+            // Do not delete files; at least for the lucene index, they are likely outside
the run/databases. 
+            if ( database instanceof DatasetGraphText ) {
+                DatasetGraphText dbtext = (DatasetGraphText)database;
+                database = dbtext.getBase();
+                dbtext.getTextIndex().close();
+                tryToRemoveFiles = false ;
+            }
+
+            boolean isTDB1 = org.apache.jena.tdb.sys.TDBInternal.isTDB1(database);
+            boolean isTDB2 = org.apache.jena.tdb2.sys.TDBInternal.isTDB2(database);
+            
+            if ( ( isTDB1 || isTDB2 ) ) {
+                // JENA-1586: Remove database from the process.
+                if ( isTDB1 )
+                    org.apache.jena.tdb.sys.TDBInternal.expel(database);
+                if ( isTDB2 )
+                    org.apache.jena.tdb2.sys.TDBInternal.expel(database);
+            
+                // JENA-1481: Really delete files.
+                // Find the database files (may not be any - e.g. in-memory).
+                Path pDatabase = FusekiSystem.dirDatabases.resolve(filename);
+                if ( tryToRemoveFiles && Files.exists(pDatabase)) {
+                    try { 
+                        if ( Files.isSymbolicLink(pDatabase)) {
+                            action.log.info(format("[%d] Database is a symbolic link, not
removing files", action.id, pDatabase)) ;
+                        } else {
+                            IO.deleteAll(pDatabase);
+                            action.log.info(format("[%d] Deleted database files %s", action.id,
pDatabase)) ;
+                        }
+                    } catch (RuntimeIOException ex) {
+                        action.log.error(format("[%d] Error while deleting database files
%s: %s", action.id, pDatabase, ex.getMessage()), ex);
+                        // But we have managed to remove it from the running server, and
removed its configuration, so declare victory. 
+                    }
+                }
+            }
+            
+            // -- System database
             // Find graph associated with this dataset name.
             // (Statically configured databases aren't in the system database.)
             Node n = NodeFactory.createLiteral(DataAccessPoint.canonical(name)) ;
@@ -328,9 +396,6 @@ public class ActionDatasets extends ActionContainerItem {
             if ( ! committed ) systemDSG.abort() ; 
             systemDSG.end() ; 
         }
-
-        // Remove the configuration file (if any).
-        action.getDataAccessPointRegistry().remove(name) ;
     }
 
     private static void assemblerFromBody(HttpAction action, StreamRDF dest) {

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/webapp/WEB-INF/web.xml b/jena-fuseki2/jena-fuseki-core/src/main/webapp/WEB-INF/web.xml
index bf2e124..48e49e8 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/webapp/WEB-INF/web.xml
+++ b/jena-fuseki2/jena-fuseki-core/src/main/webapp/WEB-INF/web.xml
@@ -257,11 +257,6 @@
   </servlet-mapping>
 
   <servlet-mapping>
-    <servlet-name>ActionStats</servlet-name>
-    <url-pattern>/$/stats/*</url-pattern>
-  </servlet-mapping>
-
-  <servlet-mapping>
     <servlet-name>ActionLogs</servlet-name>
     <url-pattern>/$/logs</url-pattern>
   </servlet-mapping>

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
index 6614f06..d3e51c4 100644
--- a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
@@ -41,6 +41,7 @@ import org.junit.runners.Suite ;
     , TestDatasetOps.class
     , TestFileUpload.class
     , TestAdmin.class
+    , TestAdminAPI.class
     , TestServerReadOnly.class
     , TestBuilder.class
 })

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
index bf41053..cf9e192 100644
--- a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
@@ -349,7 +349,6 @@ public class TestAdmin extends AbstractFusekiTest {
                 result = JSON.parseAny(in) ;
             }
         }
-        
     }
 
     private static String execSleepTask(String name, int millis) {

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdminAPI.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdminAPI.java
b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdminAPI.java
new file mode 100644
index 0000000..c0d842a
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdminAPI.java
@@ -0,0 +1,102 @@
+/**
+ * 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.jena.fuseki;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.http.HttpEntity ;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.jena.fuseki.webapp.FusekiSystem;
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.rdfconnection.RDFConnection;
+import org.apache.jena.rdfconnection.RDFConnectionFactory;
+import org.apache.jena.riot.web.HttpOp ;
+import org.apache.jena.sparql.engine.http.Params;
+import org.junit.Test ;
+
+/** More tests of the admin functionality
+ * See also TestAdmin.
+ */
+public class TestAdminAPI extends AbstractFusekiTest {
+
+    @Test public void add_delete_api_1() throws Exception {
+        testAddDelete("db_mem", "mem", false);
+    }
+    
+    @Test public void add_delete_api_2() throws Exception {
+        testAddDelete("db_tdb", "tdb", true);
+    }
+
+    @Test public void add_delete_api_3() throws Exception {
+        testAddDelete("db_tdb2", "tdb2", true);
+    }
+
+    private static void testAddDelete(String dbName, String dbType, boolean hasFiles) {
+        String URL = ServerCtl.urlRoot()+dbName;
+        String admin = ServerCtl.urlRoot()+"$/";
+        HttpEntity e = createFormEntity(dbName, "tdb");
+        
+        HttpOp.execHttpPost(admin+"datasets", e); 
+
+        RDFConnection conn = RDFConnectionFactory.connect(URL);
+        conn.update("INSERT DATA { <x:s> <x:p> 123 }");
+        int x1 = count(conn);
+        assertEquals(1, x1);
+        
+        Path pathDB = FusekiSystem.dirDatabases.resolve(dbName);
+            
+        if ( hasFiles )
+            assertTrue(Files.exists(pathDB));
+
+        HttpOp.execHttpDelete(admin+"datasets/"+dbName);
+        
+        //if ( hasFiles )
+            assertFalse(Files.exists(pathDB));
+        
+        // Recreate : no contents.
+        HttpOp.execHttpPost(admin+"datasets", e);
+        int x2 = count(conn);
+        assertEquals(0, x2);
+        if ( hasFiles )
+            assertTrue(Files.exists(pathDB));
+    }
+                              
+                              
+                              
+    static int count(RDFConnection conn) {
+        try ( QueryExecution qExec = conn.query("SELECT (count(*) AS ?C) { ?s ?p ?o }"))
{
+            return qExec.execSelect().next().getLiteral("C").getInt();
+        }
+    }
+    
+    static HttpEntity createFormEntity(String dbName, String dbType) {
+        List <? extends NameValuePair> parameters = 
+            Arrays.asList(
+                new Params.Pair("dbName", dbName),
+                new Params.Pair("dbType", dbType));
+        UrlEncodedFormEntity e = new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8);
+        return e;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/5a51311b/jena-tdb/src/main/java/org/apache/jena/tdb/sys/TDBInternal.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/sys/TDBInternal.java b/jena-tdb/src/main/java/org/apache/jena/tdb/sys/TDBInternal.java
index c241bf8..c516561 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/sys/TDBInternal.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/sys/TDBInternal.java
@@ -25,6 +25,7 @@ import org.apache.jena.atlas.lib.Lib ;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.query.Dataset ;
 import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.system.Txn;
 import org.apache.jena.tdb.StoreConnection ;
 import org.apache.jena.tdb.TDBException ;
 import org.apache.jena.tdb.base.file.Location ;
@@ -148,6 +149,15 @@ public class TDBInternal
         throw new TDBException("Not a suitable TDB-backed DatasetGraph: " + Lib.classShortName(dsg.getClass()))
;
     }
     
+    /** Stop managing a DatasetGraph. Use with great care. */
+    public static synchronized void expel(DatasetGraph dsg) {
+        DatasetGraphTDB dsgtdb = Txn.calculate(dsg, ()->getDatasetGraphTDB(dsg));
+        if ( dsgtdb == null )
+            return;
+        StoreConnection.expel(dsgtdb.getLocation(), false);
+        // No longer valid.
+    }
+    
     /** Look at a directory and see if it is a new area */
     public static boolean isNewDatabaseArea(Location location) {
         StoreConnection sConn = StoreConnection.getExisting(location) ;


Mime
View raw message