You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by to...@apache.org on 2018/09/06 10:31:52 UTC

svn commit: r1840207 - in /jackrabbit/oak/trunk: oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/f...

Author: tomekr
Date: Thu Sep  6 10:31:52 2018
New Revision: 1840207

URL: http://svn.apache.org/viewvc?rev=1840207&view=rev
Log:
OAK-7735: Support the split persistence in the SegmentNodeStoreService.

Added:
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitPersistence.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitSegmentArchiveManager.java
Modified:
    jackrabbit/oak/trunk/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureArchiveManager.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/SegmentTarManager.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/spi/persistence/SegmentArchiveManager.java

Modified: jackrabbit/oak/trunk/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureArchiveManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureArchiveManager.java?rev=1840207&r1=1840206&r2=1840207&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureArchiveManager.java (original)
+++ jackrabbit/oak/trunk/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureArchiveManager.java Thu Sep  6 10:31:52 2018
@@ -98,6 +98,12 @@ public class AzureArchiveManager impleme
     }
 
     @Override
+    public SegmentArchiveReader forceOpen(String archiveName) throws IOException {
+        CloudBlobDirectory archiveDirectory = getDirectory(archiveName);
+        return new AzureSegmentArchiveReader(archiveDirectory, ioMonitor);
+    }
+
+    @Override
     public SegmentArchiveWriter create(String archiveName) throws IOException {
         return new AzureSegmentArchiveWriter(getDirectory(archiveName), ioMonitor, monitor);
     }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java?rev=1840207&r1=1840206&r2=1840207&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java Thu Sep  6 10:31:52 2018
@@ -248,6 +248,12 @@ public class SegmentNodeStoreFactory {
         boolean customSegmentStore() default false;
 
         @AttributeDefinition(
+                name = "Split persistence",
+                description = "Boolean value indicating that the writes should be done locally when using the custom segment store"
+        )
+        boolean splitPersistence() default false;
+
+        @AttributeDefinition(
             name = "Backup directory",
             description = "Directory (relative to current working directory) for storing repository backups. " +
                 "Defaults to 'repository.home/segmentstore-backup'."
@@ -467,6 +473,11 @@ public class SegmentNodeStoreFactory {
             }
 
             @Override
+            public File getSplitPersistenceDirectory() {
+                return new File(getRepositoryHome(), appendRole("segmentstore-split"));
+            }
+
+            @Override
             public int getSegmentCacheSize() {
                 return getCacheSize("segmentCache.size", configuration.segmentCache_size());
             }
@@ -517,6 +528,11 @@ public class SegmentNodeStoreFactory {
             }
 
             @Override
+            public boolean hasSplitPersistence() {
+                return configuration.splitPersistence();
+            }
+
+            @Override
             public boolean registerDescriptors() {
                 return configuration.registerDescriptors();
             }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java?rev=1840207&r1=1840206&r2=1840207&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java Thu Sep  6 10:31:52 2018
@@ -58,7 +58,9 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.file.FileStoreStatsMBean;
 import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
 import org.apache.jackrabbit.oak.segment.file.MetricsIOMonitor;
+import org.apache.jackrabbit.oak.segment.file.tar.TarPersistence;
 import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence;
+import org.apache.jackrabbit.oak.segment.split.SplitPersistence;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
 import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo;
@@ -116,6 +118,8 @@ class SegmentNodeStoreRegistrar {
 
         File getSegmentDirectory();
 
+        File getSplitPersistenceDirectory();
+
         int getSegmentCacheSize();
 
         int getStringCacheSize();
@@ -136,6 +140,8 @@ class SegmentNodeStoreRegistrar {
 
         boolean hasCustomSegmentStore();
 
+        boolean hasSplitPersistence();
+
         boolean registerDescriptors();
 
         String getRepositoryHome();
@@ -228,8 +234,17 @@ class SegmentNodeStoreRegistrar {
         }
 
         if (cfg.hasCustomSegmentStore() && cfg.getSegmentNodeStorePersistence() != null) {
-            cfg.getLogger().info("Initializing SegmentNodeStore with custom persistence [{}]", cfg.getSegmentNodeStorePersistence());
-            builder.withCustomPersistence(cfg.getSegmentNodeStorePersistence());
+            if (cfg.hasSplitPersistence()) {
+                cfg.getLogger().info("Initializing SegmentNodeStore with custom persistence [{}] and local writes", cfg.getSegmentNodeStorePersistence());
+                cfg.getSplitPersistenceDirectory().mkdirs();
+                SegmentNodeStorePersistence roPersistence = cfg.getSegmentNodeStorePersistence();
+                SegmentNodeStorePersistence rwPersistence = new TarPersistence(cfg.getSplitPersistenceDirectory());
+                SegmentNodeStorePersistence persistence = new SplitPersistence(roPersistence, rwPersistence);
+                builder.withCustomPersistence(persistence);
+            } else {
+                cfg.getLogger().info("Initializing SegmentNodeStore with custom persistence [{}]", cfg.getSegmentNodeStorePersistence());
+                builder.withCustomPersistence(cfg.getSegmentNodeStorePersistence());
+            }
         }
 
         if (cfg.isStandbyInstance()) {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java?rev=1840207&r1=1840206&r2=1840207&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java Thu Sep  6 10:31:52 2018
@@ -246,6 +246,12 @@ public class SegmentNodeStoreService {
         boolean customSegmentStore() default false;
 
         @AttributeDefinition(
+                name = "Split persistence",
+                description = "Boolean value indicating that the writes should be done locally when using the custom segment store"
+        )
+        boolean splitPersistence() default false;
+
+        @AttributeDefinition(
             name = "Backup directory",
             description = "Directory (relative to current working directory) for storing repository backups. " +
                 "Defaults to 'repository.home/segmentstore-backup'."
@@ -403,6 +409,11 @@ public class SegmentNodeStoreService {
             }
 
             @Override
+            public File getSplitPersistenceDirectory() {
+                return new File(getRepositoryHome(), "segmentstore-split");
+            }
+
+            @Override
             public int getSegmentCacheSize() {
                 Integer size = Integer.getInteger("segmentCache.size");
                 if (size != null) {
@@ -473,6 +484,11 @@ public class SegmentNodeStoreService {
             }
 
             @Override
+            public boolean hasSplitPersistence() {
+                return configuration.splitPersistence();
+            }
+
+            @Override
             public boolean registerDescriptors() {
                 return true;
             }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/SegmentTarManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/SegmentTarManager.java?rev=1840207&r1=1840206&r2=1840207&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/SegmentTarManager.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/SegmentTarManager.java Thu Sep  6 10:31:52 2018
@@ -116,6 +116,11 @@ public class SegmentTarManager implement
     }
 
     @Override
+    public SegmentArchiveReader forceOpen(String archiveName) throws IOException {
+        return open(archiveName);
+    }
+
+    @Override
     public SegmentArchiveWriter create(String archiveName) {
         return new SegmentTarWriter(new File(segmentstoreDir, archiveName), fileStoreMonitor, ioMonitor);
     }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/spi/persistence/SegmentArchiveManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/spi/persistence/SegmentArchiveManager.java?rev=1840207&r1=1840206&r2=1840207&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/spi/persistence/SegmentArchiveManager.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/spi/persistence/SegmentArchiveManager.java Thu Sep  6 10:31:52 2018
@@ -47,12 +47,23 @@ public interface SegmentArchiveManager {
      * Opens a given archive for reading.
      *
      * @param archiveName
-     * @return the archive reader or null if the archive doesn't exist
+     * @return the archive reader or null if the archive doesn't exist or doesn't
+     * have a valid index
      */
     @Nullable
     SegmentArchiveReader open(@NotNull String archiveName) throws IOException;
 
     /**
+     * Opens an archive that wasn't closed correctly.
+     *
+     * @param archiveName
+     * @return the archive reader or null if the implementation doesn't support
+     * opening an unclosed archive
+     */
+    @Nullable
+    SegmentArchiveReader forceOpen(String archiveName) throws IOException;
+
+    /**
      * Creates a new archive.
      *
      * @param archiveName

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitPersistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitPersistence.java?rev=1840207&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitPersistence.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitPersistence.java Thu Sep  6 10:31:52 2018
@@ -0,0 +1,136 @@
+/*
+ * 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.jackrabbit.oak.segment.split;
+
+import org.apache.jackrabbit.oak.segment.spi.monitor.FileStoreMonitor;
+import org.apache.jackrabbit.oak.segment.spi.monitor.FileStoreMonitorAdapter;
+import org.apache.jackrabbit.oak.segment.spi.monitor.IOMonitor;
+import org.apache.jackrabbit.oak.segment.spi.monitor.IOMonitorAdapter;
+import org.apache.jackrabbit.oak.segment.spi.persistence.GCJournalFile;
+import org.apache.jackrabbit.oak.segment.spi.persistence.JournalFile;
+import org.apache.jackrabbit.oak.segment.spi.persistence.JournalFileReader;
+import org.apache.jackrabbit.oak.segment.spi.persistence.JournalFileWriter;
+import org.apache.jackrabbit.oak.segment.spi.persistence.ManifestFile;
+import org.apache.jackrabbit.oak.segment.spi.persistence.RepositoryLock;
+import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveManager;
+import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Properties;
+
+public class SplitPersistence implements SegmentNodeStorePersistence {
+
+    private final SegmentNodeStorePersistence roPersistence;
+
+    private final SegmentNodeStorePersistence rwPersistence;
+
+    private final Optional<String> lastRoArchive;
+
+    public SplitPersistence(SegmentNodeStorePersistence roPersistence, SegmentNodeStorePersistence rwPersistence) throws IOException {
+        this.roPersistence = roPersistence;
+        this.rwPersistence = rwPersistence;
+
+        ManifestFile manifest = rwPersistence.getManifestFile();
+        if (!manifest.exists()) {
+            initialize();
+        }
+        Properties properties = manifest.load();
+        lastRoArchive = Optional.ofNullable(properties.getProperty("split.lastRoArchive"));
+    }
+
+    private void initialize() throws IOException {
+        Properties properties = roPersistence.getManifestFile().load();
+        properties.setProperty("split.initialized", "true");
+        Optional<String> lastArchive = getLastArchive();
+        lastArchive.ifPresent(a -> properties.setProperty("split.lastRoArchive", a));
+        rwPersistence.getManifestFile().save(properties);
+
+        GCJournalFile gcJournalFile = rwPersistence.getGCJournalFile();
+        for (String line : roPersistence.getGCJournalFile().readLines()) {
+            gcJournalFile.writeLine(line);
+        }
+
+        List<String> journalLines = new ArrayList<>();
+        try (JournalFileReader journalFileReader = roPersistence.getJournalFile().openJournalReader()) {
+            String journalLine;
+            while ((journalLine = journalFileReader.readLine()) != null) {
+                journalLines.add(journalLine);
+            }
+        }
+
+        Collections.reverse(journalLines);
+
+        try (JournalFileWriter journalFileWriter = rwPersistence.getJournalFile().openJournalWriter()) {
+            for (String line : journalLines) {
+                journalFileWriter.writeLine(line);
+            }
+        }
+    }
+
+    private Optional<String> getLastArchive() throws IOException {
+        SegmentArchiveManager manager = roPersistence.createArchiveManager(false, new IOMonitorAdapter(), new FileStoreMonitorAdapter());
+        List<String> archives = manager.listArchives();
+        if (archives.isEmpty()) {
+            return Optional.empty();
+        } else {
+            Collections.sort(archives);
+            return Optional.of(archives.get(archives.size() - 1));
+        }
+    }
+
+    @Override
+    public SegmentArchiveManager createArchiveManager(boolean memoryMapping, IOMonitor ioMonitor, FileStoreMonitor fileStoreMonitor) throws IOException {
+        if (lastRoArchive.isPresent()) {
+            return new SplitSegmentArchiveManager(
+                    roPersistence.createArchiveManager(memoryMapping, ioMonitor, fileStoreMonitor),
+                    rwPersistence.createArchiveManager(memoryMapping, ioMonitor, fileStoreMonitor),
+                    lastRoArchive.get());
+        } else {
+            return rwPersistence.createArchiveManager(memoryMapping, ioMonitor, fileStoreMonitor);
+        }
+    }
+
+    @Override
+    public boolean segmentFilesExist() {
+        return lastRoArchive.isPresent() || rwPersistence.segmentFilesExist();
+    }
+
+    @Override
+    public JournalFile getJournalFile() {
+        return rwPersistence.getJournalFile();
+    }
+
+    @Override
+    public GCJournalFile getGCJournalFile() throws IOException {
+        return rwPersistence.getGCJournalFile();
+    }
+
+    @Override
+    public ManifestFile getManifestFile() throws IOException {
+        return rwPersistence.getManifestFile();
+    }
+
+    @Override
+    public RepositoryLock lockRepository() throws IOException {
+        return rwPersistence.lockRepository();
+    }
+
+}

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitSegmentArchiveManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitSegmentArchiveManager.java?rev=1840207&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitSegmentArchiveManager.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/split/SplitSegmentArchiveManager.java Thu Sep  6 10:31:52 2018
@@ -0,0 +1,133 @@
+/*
+ * 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.jackrabbit.oak.segment.split;
+
+import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveManager;
+import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveReader;
+import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveWriter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.UUID;
+
+public class SplitSegmentArchiveManager implements SegmentArchiveManager {
+
+    private final SegmentArchiveManager roArchiveManager;
+
+    private final SegmentArchiveManager rwArchiveManager;
+
+    private final List<String> roArchiveList;
+
+    public SplitSegmentArchiveManager(SegmentArchiveManager roArchiveManager, SegmentArchiveManager rwArchiveManager, String lastRoArchive) throws IOException {
+        this.roArchiveManager = roArchiveManager;
+        this.rwArchiveManager = rwArchiveManager;
+        this.roArchiveList = getRoArchives(lastRoArchive);
+    }
+
+    private List<String> getRoArchives(String lastRoArchive) throws IOException {
+        List<String> archives = roArchiveManager.listArchives();
+        Collections.sort(archives);
+        int index = archives.indexOf(lastRoArchive);
+        if (index == -1) {
+            throw new IllegalStateException("Can't find archive " + lastRoArchive + " in the read-only persistence");
+        }
+        return new ArrayList<>(archives.subList(0, index + 1));
+    }
+
+    @Override
+    public @NotNull List<String> listArchives() throws IOException {
+        List<String> result = new ArrayList<>();
+        result.addAll(roArchiveList);
+        result.addAll(rwArchiveManager.listArchives());
+        return result;
+    }
+
+    @Override
+    public @Nullable SegmentArchiveReader open(@NotNull String archiveName) throws IOException {
+        if (roArchiveList.contains(archiveName)) {
+            try {
+                return roArchiveManager.open(archiveName);
+            } catch (IOException e) {
+                return roArchiveManager.forceOpen(archiveName);
+            }
+        } else {
+            return rwArchiveManager.open(archiveName);
+        }
+    }
+
+    @Override
+    public @Nullable SegmentArchiveReader forceOpen(String archiveName) throws IOException {
+        if (roArchiveList.contains(archiveName)) {
+            return roArchiveManager.forceOpen(archiveName);
+        } else {
+            return rwArchiveManager.forceOpen(archiveName);
+        }
+    }
+
+    @Override
+    public @NotNull SegmentArchiveWriter create(@NotNull String archiveName) throws IOException {
+        return rwArchiveManager.create(archiveName);
+    }
+
+    @Override
+    public boolean delete(@NotNull String archiveName) {
+        if (roArchiveList.contains(archiveName)) {
+            return false;
+        } else {
+            return rwArchiveManager.delete(archiveName);
+        }
+    }
+
+    @Override
+    public boolean renameTo(@NotNull String from, @NotNull String to) {
+        if (roArchiveList.contains(from) || roArchiveList.contains(to)) {
+            return false;
+        } else {
+            return rwArchiveManager.renameTo(from, to);
+        }
+    }
+
+    @Override
+    public void copyFile(@NotNull String from, @NotNull String to) throws IOException {
+        if (roArchiveList.contains(to)) {
+            throw new IOException("Can't overwrite the read-only " + to);
+        } else if (roArchiveList.contains(from)) {
+            throw new IOException("Can't copy the archive between persistances " + from + " -> " + to);
+        } else {
+            rwArchiveManager.copyFile(from, to);
+        }
+    }
+
+    @Override
+    public boolean exists(@NotNull String archiveName) {
+        return roArchiveList.contains(archiveName) || rwArchiveManager.exists(archiveName);
+    }
+
+    @Override
+    public void recoverEntries(@NotNull String archiveName, @NotNull LinkedHashMap<UUID, byte[]> entries) throws IOException {
+        if (roArchiveList.contains(archiveName)) {
+            roArchiveManager.recoverEntries(archiveName, entries);
+        } else {
+            rwArchiveManager.recoverEntries(archiveName, entries);
+        }
+    }
+}