You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2022/04/03 10:20:26 UTC

[jena] branch main updated: GH-1225: Safe write of spatial index

This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/main by this push:
     new 36f985b  GH-1225: Safe write of spatial index
     new 186a071  Merge pull request #1238 from afs/safe-write
36f985b is described below

commit 36f985b13d4965da158403e9bbafc8e76e287b66
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Sat Mar 26 14:34:26 2022 +0000

    GH-1225: Safe write of spatial index
---
 .../main/java/org/apache/jena/atlas/io/IOX.java    | 24 +++++++++++
 .../jena/geosparql/spatial/SpatialIndex.java       | 49 ++++++++++------------
 2 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java b/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java
index 181e8e4..75f0731 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java
@@ -104,6 +104,20 @@ public class IOX {
         } catch(IOException ex) { throw IOX.exception(ex); }
     }
 
+    /** Write a file safely, but allow system to use copy-delete if the chnage can not be done atomically.
+     *  Prefer {@link #safeWrite} which requires an atomic move.
+     */
+    public static boolean safeWriteOrCopy(Path file, Path tmpFile, IOConsumer<OutputStream> writerAction) {
+        try {
+            try(OutputStream out = new BufferedOutputStream(Files.newOutputStream(tmpFile)) ) {
+                writerAction.actionEx(out);
+            }
+            moveAllowCopy(tmpFile, file);
+            return true;
+        } catch(IOException ex) { throw IOX.exception(ex); }
+    }
+
+
     /** Delete a file. */
     public static void delete(Path path) {
         try { Files.delete(path); }
@@ -122,6 +136,16 @@ public class IOX {
         }
     }
 
+    /** Move a file, allowing the system to copy-delete it if it can not be moved atomically. */
+    public static void moveAllowCopy(Path src, Path dst) {
+        try { Files.move(src, dst); }
+        catch (IOException ex) {
+            FmtLog.error(IOX.class, ex, "IOException moving %s to %s", src, dst);
+            throw IOX.exception(ex);
+        }
+    }
+
+
     public static void deleteAll(String start) {
         deleteAll(Paths.get(start));
     }
diff --git a/jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/SpatialIndex.java b/jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/SpatialIndex.java
index 952ca1f..63f48f2 100644
--- a/jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/SpatialIndex.java
+++ b/jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/SpatialIndex.java
@@ -17,19 +17,14 @@
  */
 package org.apache.jena.geosparql.spatial;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.*;
 import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+
+import org.apache.jena.atlas.RuntimeIOException;
+import org.apache.jena.atlas.io.IOX;
 import org.apache.jena.geosparql.configuration.GeoSPARQLOperations;
 import org.apache.jena.geosparql.implementation.GeometryWrapper;
 import org.apache.jena.geosparql.implementation.SRSInfo;
@@ -40,14 +35,7 @@ import org.apache.jena.geosparql.implementation.vocabulary.SpatialExtension;
 import org.apache.jena.query.Dataset;
 import org.apache.jena.query.DatasetFactory;
 import org.apache.jena.query.ReadWrite;
-import org.apache.jena.rdf.model.Literal;
-import org.apache.jena.rdf.model.Model;
-import org.apache.jena.rdf.model.NodeIterator;
-import org.apache.jena.rdf.model.RDFNode;
-import org.apache.jena.rdf.model.ResIterator;
-import org.apache.jena.rdf.model.Resource;
-import org.apache.jena.rdf.model.Statement;
-import org.apache.jena.rdf.model.StmtIterator;
+import org.apache.jena.rdf.model.*;
 import org.apache.jena.sparql.engine.ExecutionContext;
 import org.apache.jena.sparql.util.Context;
 import org.apache.jena.sparql.util.Symbol;
@@ -534,20 +522,25 @@ public class SpatialIndex {
         if (spatialIndexFile != null) {
             LOGGER.info("Saving Spatial Index - Started: {}", spatialIndexFile.getAbsolutePath());
             SpatialIndexStorage storage = new SpatialIndexStorage(spatialIndexItems, srsURI);
-            File file;
+            String filename = spatialIndexFile.getAbsolutePath();
+            Path file = Path.of(filename);
+            Path tmpFile = IOX.uniqueDerivedPath(file, null);
             try {
-                file = File.createTempFile("spatial_index", null);
-                file.deleteOnExit();
-                try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
-                    out.writeObject(storage);
-                    FileUtils.copyFile(file, spatialIndexFile);
-                }
+                Files.deleteIfExists(file);
             } catch (IOException ex) {
+                throw new SpatialIndexException("Failed to delete file: " + ex.getMessage());
+            }
+            try {
+                IOX.safeWriteOrCopy(file, tmpFile,
+                                    out->{
+                                        ObjectOutputStream oos = new ObjectOutputStream(out);
+                                        oos.writeObject(storage);
+                                    });
+            } catch (RuntimeIOException ex) {
                 throw new SpatialIndexException("Save Exception: " + ex.getMessage());
             } finally {
                 LOGGER.info("Saving Spatial Index - Completed: {}", spatialIndexFile.getAbsolutePath());
             }
         }
     }
-
 }