From 88d4e15ddd8561f20a1af55263efd8614f072200 Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Tue, 08 Jan 2019 21:18:05 +0000
Subject: [PATCH] Using kryo instead of fst for object serialization (is 50% faster).

---
 borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ArchiveFilelistCache.java |   54 +++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ArchiveFilelistCache.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ArchiveFilelistCache.java
index 5b7abcc..b81a191 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ArchiveFilelistCache.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ArchiveFilelistCache.java
@@ -1,5 +1,8 @@
 package de.micromata.borgbutler.cache;
 
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
 import de.micromata.borgbutler.config.BorgRepoConfig;
 import de.micromata.borgbutler.data.Archive;
 import de.micromata.borgbutler.data.FileSystemFilter;
@@ -9,13 +12,13 @@
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
 import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
-import org.nustaq.serialization.FSTConfiguration;
-import org.nustaq.serialization.FSTObjectInput;
-import org.nustaq.serialization.FSTObjectOutput;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.nio.file.Files;
@@ -31,6 +34,7 @@
  * The compression is also useful for faster reading from the filesystem.
  */
 class ArchiveFilelistCache {
+    private static final String SERIALIZATION_ID_STRING = "kryo 5.0.0-RC1";
     private static Logger log = LoggerFactory.getLogger(ArchiveFilelistCache.class);
     private static final String CACHE_ARCHIVE_LISTS_BASENAME = "archive-content-";
     private static final String CACHE_FILE_GZIP_EXTENSION = ".gz";
@@ -40,13 +44,10 @@
     private long FILES_EXPIRE_TIME = 7 * 24 * 3660 * 1000; // Expires after 7 days.
     // For avoiding concurrent writing of same files (e. g. after the user has pressed a button twice).
     private Set<File> savingFiles = new HashSet<>();
-    final FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();
 
     ArchiveFilelistCache(File cacheDir, int cacheArchiveContentMaxDiscSizeMB) {
         this.cacheDir = cacheDir;
         this.cacheArchiveContentMaxDiscSizeMB = cacheArchiveContentMaxDiscSizeMB;
-        conf.registerClass(Integer.class, BorgFilesystemItem.class);
-        conf.setShareReferences(false);
     }
 
     public void save(BorgRepoConfig repoConfig, Archive archive, List<BorgFilesystemItem> filesystemItems) {
@@ -67,16 +68,16 @@
             log.info("Saving archive content as file list: " + file.getAbsolutePath());
 
             int fileNumber = -1;
-            try (FSTObjectOutput outputStream
-                         = new FSTObjectOutput(new BufferedOutputStream(new GzipCompressorOutputStream(new FileOutputStream(file))), conf)) {
-                outputStream.writeObject(filesystemItems.size(), Integer.class);
+            Kryo kryo = createKryo();
+            try (Output outputStream = new Output(new GzipCompressorOutputStream(new FileOutputStream(file)))) {
+                kryo.writeObject(outputStream, SERIALIZATION_ID_STRING);
+                kryo.writeObject(outputStream, filesystemItems.size());
                 Iterator<BorgFilesystemItem> it = filesystemItems.iterator();
                 while (it.hasNext()) {
                     BorgFilesystemItem item = it.next();
                     item.setFileNumber(++fileNumber);
-                    outputStream.writeObject(item, BorgFilesystemItem.class);
+                    kryo.writeObject(outputStream, item);
                 }
-                outputStream.writeObject("EOF");
             } catch (IOException ex) {
                 log.error("Error while writing file list '" + file.getAbsolutePath() + "': " + ex.getMessage(), ex);
             }
@@ -142,7 +143,7 @@
      * @param filter  If given, only file items matching this filter are returned.
      * @return
      */
-    public List<BorgFilesystemItem> load(File file, Archive archive, FileSystemFilter filter) {
+    public List<BorgFilesystemItem> load(File file, Archive archive, FileSystemFilter filter) throws RuntimeException {
         if (!file.exists()) {
             log.error("File '" + file.getAbsolutePath() + "' doesn't exist. Can't get archive content files.");
             return null;
@@ -157,17 +158,25 @@
         List<BorgFilesystemItem> list = new ArrayList<>();
         long millis = System.currentTimeMillis();
         // GZipCompressorInputStream buffers already, no BufferedInputReader needed.
-        try (FSTObjectInput inputStream = new FSTObjectInput(new GzipCompressorInputStream(new FileInputStream(file)), conf)) {
-            int size = (Integer) inputStream.readObject(Integer.class);
+        Kryo kryo = createKryo();
+        try (Input inputStream = new Input(new GzipCompressorInputStream(new FileInputStream(file)))) {
+            String serializationId = kryo.readObject(inputStream, String.class);
+            if (!SERIALIZATION_ID_STRING.equals(serializationId)) {
+                log.info("Incompatible archive cache file format. Expected id '" + SERIALIZATION_ID_STRING + "', but received: '" + serializationId
+                + "'. OK, trying to get the data from Borg again.");
+                return null;
+            }
+            int size = kryo.readObject(inputStream, Integer.class);
             for (int i = 0; i < size; i++) {
-                BorgFilesystemItem item = (BorgFilesystemItem) inputStream.readObject(BorgFilesystemItem.class);
+                BorgFilesystemItem item = kryo.readObject(inputStream, BorgFilesystemItem.class);
                 if (filter == null || filter.matches(item)) {
                     list.add(item);
                     if (filter != null && filter.isFinished()) break;
                 }
             }
         } catch (Exception ex) {
-            log.error("Error while reading file list '" + file.getAbsolutePath() + "': " + ex.getMessage(), ex);
+            log.error("Error while reading file list '" + file.getAbsolutePath() + "': " + ex.getMessage() + ". OK, trying to get the data from Borg again.");
+            return null;
         }
         BigDecimal bd = new BigDecimal(System.currentTimeMillis() - millis).divide(THOUSAND, 1, RoundingMode.HALF_UP);
         log.info("Loading of " + String.format("%,d", list.size()) + " file system items done in " + bd + " seconds.");
@@ -286,5 +295,16 @@
     private boolean isCacheFile(File file) {
         return file.getName().startsWith(CACHE_ARCHIVE_LISTS_BASENAME);
     }
+
+
+    private Kryo createKryo() {
+        Kryo kryo = new Kryo();
+        kryo.register(BorgFilesystemItem.class, 9);
+        kryo.register(BorgFilesystemItem.DiffStatus.class, 10);
+        kryo.setMaxDepth(10);
+        kryo.setWarnUnregisteredClasses(true);
+        kryo.setReferences(false);
+        return kryo;
+    }
 }
 

--
Gitblit v1.10.0