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

nizhikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 9262765bb73 IGNITE-25428 Move defragmentation logic to CacheFileTree  
(#12094)
9262765bb73 is described below

commit 9262765bb73bb4f1be09cb8e05ffab030b570f68
Author: Nikolay <[email protected]>
AuthorDate: Mon May 26 12:31:00 2025 +0300

    IGNITE-25428 Move defragmentation logic to CacheFileTree  (#12094)
---
 .../internal/processors/cache/CachesRegistry.java  |   5 +-
 .../processors/cache/GridLocalConfigManager.java   |   7 +-
 .../CachePartitionDefragmentationManager.java      |  74 +++---
 .../defragmentation/DefragmentationFileUtils.java  | 244 +++++--------------
 .../persistence/file/FilePageStoreManager.java     |  96 ++++----
 .../cache/persistence/filename/CacheFileTree.java  | 258 +++++++++++++++++++++
 .../cache/persistence/filename/NodeFileTree.java   |  19 +-
 .../persistence/IgnitePdsDefragmentationTest.java  |  63 +++--
 .../db/IgnitePdsCheckpointRecoveryTest.java        |   6 +-
 .../persistence/filename/FileTreeTestUtils.java    |  32 +++
 .../IgnitePdsIndexingDefragmentationTest.java      |  11 +-
 11 files changed, 476 insertions(+), 339 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
index 412e1a20b12..90013c11369 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
@@ -272,10 +272,7 @@ public class CachesRegistry {
         // Pre-create cache work directories if they don't exist.
         for (StoredCacheData data : cacheConfigsToPersist) {
             try {
-                FilePageStoreManager.checkAndInitCacheWorkDir(
-                    
cctx.kernalContext().pdsFolderResolver().fileTree().cacheStorage(data.config()),
-                    log
-                );
+                
FilePageStoreManager.checkAndInitCacheWorkDir(cctx.kernalContext().pdsFolderResolver().fileTree().cacheTree(data.config()));
             }
             catch (IgniteCheckedException e) {
                 if (!cctx.kernalContext().isStopping()) {
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridLocalConfigManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridLocalConfigManager.java
index 8477df516f6..e0b1241b257 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridLocalConfigManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridLocalConfigManager.java
@@ -56,6 +56,7 @@ import org.apache.ignite.failure.FailureContext;
 import org.apache.ignite.failure.FailureType;
 import org.apache.ignite.internal.GridKernalContext;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.FileTreeUtils;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree;
 import org.apache.ignite.internal.util.typedef.F;
@@ -269,11 +270,11 @@ public class GridLocalConfigManager {
         if (!CU.storeCacheConfig(cacheProcessor.context(), ccfg))
             return;
 
-        File cacheWorkDir = ft.cacheStorage(ccfg);
+        CacheFileTree cft = ft.cacheTree(ccfg);
 
-        FilePageStoreManager.checkAndInitCacheWorkDir(cacheWorkDir, log);
+        FilePageStoreManager.checkAndInitCacheWorkDir(cft);
 
-        assert cacheWorkDir.exists() : "Work directory does not exist: " + 
cacheWorkDir;
+        assert cft.storage().exists() : "Work directory does not exist: " + 
cft.storage();
 
         File file = ft.cacheConfigurationFile(ccfg);
         Path filePath = file.toPath();
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/CachePartitionDefragmentationManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/CachePartitionDefragmentationManager.java
index 6e589b1f718..9af8150f109 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/CachePartitionDefragmentationManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/CachePartitionDefragmentationManager.java
@@ -17,7 +17,6 @@
 
 package 
org.apache.ignite.internal.processors.cache.persistence.defragmentation;
 
-import java.io.File;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -58,6 +57,7 @@ import 
org.apache.ignite.internal.processors.cache.persistence.checkpoint.Checkp
 import 
org.apache.ignite.internal.processors.cache.persistence.checkpoint.LightweightCheckpointManager;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FileVersionCheckingFactory;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree;
 import 
org.apache.ignite.internal.processors.cache.persistence.freelist.AbstractFreeList;
 import 
org.apache.ignite.internal.processors.cache.persistence.freelist.SimpleDataRow;
@@ -96,11 +96,6 @@ import static 
org.apache.ignite.internal.processors.cache.persistence.Checkpoint
 import static 
org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.DEFRAGMENTATION_MAPPING_REGION_NAME;
 import static 
org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.DEFRAGMENTATION_PART_REGION_NAME;
 import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.batchRenameDefragmentedCacheGroupPartitions;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedIndexFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedIndexTmpFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedPartFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedPartMappingFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedPartTmpFile;
 import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.renameTempIndexFile;
 import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.renameTempPartitionFile;
 import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.skipAlreadyDefragmentedCacheGroup;
@@ -296,11 +291,11 @@ public class CachePartitionDefragmentationManager {
             for (CacheGroupContext oldGrpCtx : cacheGrpCtxsForDefragmentation) 
{
                 int grpId = oldGrpCtx.groupId();
 
-                File workDir = ft.cacheStorage(oldGrpCtx.config());
+                CacheFileTree cft = ft.cacheTree(oldGrpCtx.config());
 
                 List<CacheDataStore> oldCacheDataStores = oldStores.get(grpId);
 
-                if (skipAlreadyDefragmentedCacheGroup(workDir, grpId, log)) {
+                if (skipAlreadyDefragmentedCacheGroup(cft, log)) {
                     status.onCacheGroupSkipped(oldGrpCtx, 
oldCacheDataStores.size());
 
                     continue;
@@ -311,7 +306,7 @@ public class CachePartitionDefragmentationManager {
 
                     status.onCacheGroupStart(oldGrpCtx, 
oldCacheDataStores.size());
 
-                    if (workDir == null || oldCacheDataStores.isEmpty()) {
+                    if (oldCacheDataStores.isEmpty()) {
                         status.onCacheGroupFinish(oldGrpCtx);
 
                         continue;
@@ -357,7 +352,7 @@ public class CachePartitionDefragmentationManager {
 
                     AtomicLong idxAllocationTracker = new GridAtomicLong();
 
-                    createIndexPageStore(grpId, workDir, pageStoreFactory, 
partDataRegion, idxAllocationTracker::addAndGet);
+                    createIndexPageStore(cft, pageStoreFactory, 
partDataRegion, idxAllocationTracker::addAndGet);
 
                     checkCancellation();
 
@@ -398,8 +393,7 @@ public class CachePartitionDefragmentationManager {
                         oldCacheDataStores,
                         oldCacheDataStore -> defragmentOnePartition(
                             oldGrpCtx,
-                            grpId,
-                            workDir,
+                            cft,
                             offheap,
                             pageStoreFactory,
                             cmpFut,
@@ -433,8 +427,8 @@ public class CachePartitionDefragmentationManager {
                                 "oldPages", oldIdxPageStore.pages(), false,
                                 "newPages", idxAllocationTracker.get() + 1, 
false,
                                 "pageSize", pageSize, false,
-                                "partFile", 
defragmentedIndexFile(workDir).getName(), false,
-                                "workDir", workDir, false
+                                "partFile", 
cft.defragmentedIndexFile().getName(), false,
+                                "workDir", cft.storage(), false
                             ));
                         }
 
@@ -454,9 +448,9 @@ public class CachePartitionDefragmentationManager {
 
                         pageMgr.pageStoreMap().clear(grpId);
 
-                        renameTempIndexFile(workDir);
+                        renameTempIndexFile(cft);
 
-                        
writeDefragmentationCompletionMarker(filePageStoreMgr.getPageStoreFileIoFactory(),
 workDir, log);
+                        
writeDefragmentationCompletionMarker(filePageStoreMgr.getPageStoreFileIoFactory(),
 cft, log);
 
                         try {
                             for (PageStore store : 
filePageStoreMgr.getStores(grpId))
@@ -466,7 +460,7 @@ public class CachePartitionDefragmentationManager {
                             throw new IgniteException("Failed to stop page 
store for group " + grpId, e);
                         }
 
-                        batchRenameDefragmentedCacheGroupPartitions(workDir, 
log);
+                        batchRenameDefragmentedCacheGroupPartitions(cft);
 
                         return null;
                     });
@@ -478,7 +472,7 @@ public class CachePartitionDefragmentationManager {
                     );
                 }
                 catch (DefragmentationCancelledException e) {
-                    DefragmentationFileUtils.deleteLeftovers(workDir);
+                    DefragmentationFileUtils.deleteLeftovers(cft);
 
                     throw e;
                 }
@@ -523,8 +517,7 @@ public class CachePartitionDefragmentationManager {
      */
     private boolean defragmentOnePartition(
         CacheGroupContext oldGrpCtx,
-        int grpId,
-        File workDir,
+        CacheFileTree cft,
         GridCacheOffheapManager offheap,
         FileVersionCheckingFactory pageStoreFactory,
         GridCompoundFuture<Object, Object> cmpFut,
@@ -539,8 +532,7 @@ public class CachePartitionDefragmentationManager {
         int partId = oldCacheDataStore.partId();
 
         PartitionContext partCtx = new PartitionContext(
-            workDir,
-            grpId,
+            cft.groupId(),
             partId,
             partDataRegion,
             mappingDataRegion,
@@ -550,9 +542,9 @@ public class CachePartitionDefragmentationManager {
             pageStoreFactory
         );
 
-        if (skipAlreadyDefragmentedPartition(workDir, grpId, partId, log)) {
+        if (skipAlreadyDefragmentedPartition(cft, partId, log)) {
             partCtx.createPageStore(
-                () -> defragmentedPartMappingFile(workDir, partId).toPath(),
+                () -> cft.defragmentedPartMappingFile(partId).toPath(),
                 partCtx.mappingPagesAllocated,
                 partCtx.mappingPageMemory
             );
@@ -563,7 +555,7 @@ public class CachePartitionDefragmentationManager {
         }
 
         partCtx.createPageStore(
-            () -> defragmentedPartMappingFile(workDir, partId).toPath(),
+            () -> cft.defragmentedPartMappingFile(partId).toPath(),
             partCtx.mappingPagesAllocated,
             partCtx.mappingPageMemory
         );
@@ -573,7 +565,7 @@ public class CachePartitionDefragmentationManager {
         checkCancellation();
 
         partCtx.createPageStore(
-            () -> defragmentedPartTmpFile(workDir, partId).toPath(),
+            () -> cft.defragmentedPartTmpFile(partId).toPath(),
             partCtx.partPagesAllocated,
             partCtx.partPageMemory
         );
@@ -584,7 +576,7 @@ public class CachePartitionDefragmentationManager {
 
         DefragmentationPageReadWriteManager pageMgr = 
(DefragmentationPageReadWriteManager)partCtx.partPageMemory.pageManager();
 
-        PageStore oldPageStore = filePageStoreMgr.getStore(grpId, partId);
+        PageStore oldPageStore = filePageStoreMgr.getStore(cft.groupId(), 
partId);
 
         status.onPartitionDefragmented(
             oldGrpCtx,
@@ -598,24 +590,24 @@ public class CachePartitionDefragmentationManager {
                 if (log.isDebugEnabled()) {
                     log.debug(S.toString(
                         "Partition defragmented",
-                        "grpId", grpId, false,
+                        "grpId", cft.groupId(), false,
                         "partId", partId, false,
                         "oldPages", oldPageStore.pages(), false,
                         "newPages", partCtx.partPagesAllocated.get() + 1, 
false,
                         "mappingPages", partCtx.mappingPagesAllocated.get() + 
1, false,
                         "pageSize", pageSize, false,
-                        "partFile", defragmentedPartFile(workDir, 
partId).getName(), false,
-                        "workDir", workDir, false
+                        "partFile", 
cft.defragmentedPartFile(partId).getName(), false,
+                        "workDir", cft.storage(), false
                     ));
                 }
 
-                oldPageMem.invalidate(grpId, partId);
+                oldPageMem.invalidate(cft.groupId(), partId);
 
-                partCtx.partPageMemory.invalidate(grpId, partId);
+                partCtx.partPageMemory.invalidate(cft.groupId(), partId);
 
-                pageMgr.pageStoreMap().removePageStore(grpId, partId); // Yes, 
it'll be invalid in a second.
+                pageMgr.pageStoreMap().removePageStore(cft.groupId(), partId); 
// Yes, it'll be invalid in a second.
 
-                renameTempPartitionFile(workDir, partId);
+                renameTempPartitionFile(cft, partId);
             }
         };
 
@@ -637,8 +629,7 @@ public class CachePartitionDefragmentationManager {
 
     /** */
     public void createIndexPageStore(
-        int grpId,
-        File workDir,
+        CacheFileTree cft,
         FileVersionCheckingFactory pageStoreFactory,
         DataRegion partRegion,
         LongConsumer allocatedTracker
@@ -647,7 +638,7 @@ public class CachePartitionDefragmentationManager {
         // There is a time period when index is already defragmented but 
marker file is not created yet. If node is
         // failed in that time window then index will be deframented once 
again. That's fine, situation is rare but code
         // to fix that would add unnecessary complications.
-        U.delete(defragmentedIndexTmpFile(workDir));
+        U.delete(cft.defragmentedIndexTmpFile());
 
         PageStore idxPageStore;
 
@@ -655,7 +646,7 @@ public class CachePartitionDefragmentationManager {
         try {
             idxPageStore = pageStoreFactory.createPageStore(
                 FLAG_IDX,
-                () -> defragmentedIndexTmpFile(workDir).toPath(),
+                () -> cft.defragmentedIndexTmpFile().toPath(),
                 allocatedTracker
             );
         }
@@ -669,7 +660,7 @@ public class CachePartitionDefragmentationManager {
 
         DefragmentationPageReadWriteManager partMgr = 
(DefragmentationPageReadWriteManager)partPageMem.pageManager();
 
-        partMgr.pageStoreMap().addPageStore(grpId, INDEX_PARTITION, 
idxPageStore);
+        partMgr.pageStoreMap().addPageStore(cft.groupId(), INDEX_PARTITION, 
idxPageStore);
     }
 
     /**
@@ -931,9 +922,6 @@ public class CachePartitionDefragmentationManager {
     /** */
     @SuppressWarnings("PublicField")
     private class PartitionContext {
-        /** */
-        public final File workDir;
-
         /** */
         public final int grpId;
 
@@ -978,7 +966,6 @@ public class CachePartitionDefragmentationManager {
 
         /** */
         public PartitionContext(
-            File workDir,
             int grpId,
             int partId,
             DataRegion partDataRegion,
@@ -988,7 +975,6 @@ public class CachePartitionDefragmentationManager {
             CacheDataStore oldCacheDataStore,
             FileVersionCheckingFactory pageStoreFactory
         ) {
-            this.workDir = workDir;
             this.grpId = grpId;
             this.partId = partId;
             cacheDataRegion = oldGrpCtx.dataRegion();
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/DefragmentationFileUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/DefragmentationFileUtils.java
index 100c1b70892..bd33c4d3c93 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/DefragmentationFileUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/defragmentation/DefragmentationFileUtils.java
@@ -25,6 +25,7 @@ import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 
@@ -33,55 +34,26 @@ import static 
java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 import static java.nio.file.StandardOpenOption.CREATE_NEW;
 import static java.nio.file.StandardOpenOption.WRITE;
 import static 
org.apache.ignite.internal.pagemem.PageIdAllocator.INDEX_PARTITION;
-import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.FILE_SUFFIX;
-import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.INDEX_FILE_PREFIX;
-import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.PART_FILE_PREFIX;
-import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.TMP_SUFFIX;
-import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.partitionFileName;
+import static 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree.extractPartId;
 
 /**
  * Everything related to file management during defragmentation process.
  */
 public class DefragmentationFileUtils {
-    /** Prefix for link mapping files. */
-    private static final String DFRG_LINK_MAPPING_FILE_PREFIX = 
PART_FILE_PREFIX + "map-";
-
-    /** Link mapping file template. */
-    private static final String DFRG_LINK_MAPPING_FILE_TEMPLATE = 
DFRG_LINK_MAPPING_FILE_PREFIX + "%d" + FILE_SUFFIX;
-
-    /** Defragmentation complation marker file name. */
-    private static final String DFRG_COMPLETION_MARKER_FILE_NAME = 
"dfrg-completion-marker";
-
-    /** Name of defragmentated index partition file. */
-    private static final String DFRG_INDEX_FILE_NAME = INDEX_FILE_PREFIX + 
"-dfrg" + FILE_SUFFIX;
-
-    /** Name of defragmentated index partition temporary file. */
-    private static final String DFRG_INDEX_TMP_FILE_NAME = 
DFRG_INDEX_FILE_NAME + TMP_SUFFIX;
-
-    /** Prefix for defragmented partition files. */
-    private static final String DFRG_PARTITION_FILE_PREFIX = PART_FILE_PREFIX 
+ "dfrg-";
-
-    /** Defragmented partition file template. */
-    private static final String DFRG_PARTITION_FILE_TEMPLATE = 
DFRG_PARTITION_FILE_PREFIX + "%d" + FILE_SUFFIX;
-
-    /** Defragmented partition temp file template. */
-    private static final String DFRG_PARTITION_TMP_FILE_TEMPLATE = 
DFRG_PARTITION_FILE_TEMPLATE + TMP_SUFFIX;
-
     /**
      * Performs cleanup of work dir before initializing file page stores.
      * Will finish batch renaming if defragmentation was completed or delete 
garbage if it wasn't.
      *
-     * @param workDir Cache group working directory.
-     * @param log Logger to write messages.
+     * @param cft Cache file tree.
      * @throws IgniteCheckedException If {@link IOException} occurred.
      */
-    public static void beforeInitPageStores(File workDir, IgniteLogger log) 
throws IgniteCheckedException {
+    public static void beforeInitPageStores(CacheFileTree cft) throws 
IgniteCheckedException {
         try {
-            batchRenameDefragmentedCacheGroupPartitions(workDir, log);
+            batchRenameDefragmentedCacheGroupPartitions(cft);
 
-            U.delete(defragmentationCompletionMarkerFile(workDir));
+            U.delete(cft.defragmentationCompletionMarkerFile());
 
-            deleteLeftovers(workDir);
+            deleteLeftovers(cft);
         }
         catch (IgniteException e) {
             throw new IgniteCheckedException(e);
@@ -91,16 +63,16 @@ public class DefragmentationFileUtils {
     /**
      * Deletes all defragmentation related file from work directory, except 
for completion marker.
      *
-     * @param workDir Cache group working directory.
+     * @param cft Cache file tree.
      */
-    public static void deleteLeftovers(File workDir) {
-        for (File file : workDir.listFiles()) {
+    public static void deleteLeftovers(CacheFileTree cft) {
+        for (File file : cft.storage().listFiles()) {
             String fileName = file.getName();
 
             if (
-                fileName.startsWith(DFRG_PARTITION_FILE_PREFIX)
-                    || fileName.startsWith(DFRG_INDEX_FILE_NAME)
-                    || fileName.startsWith(DFRG_LINK_MAPPING_FILE_PREFIX)
+                CacheFileTree.isDefragmentPartition(fileName)
+                    || CacheFileTree.isDefragmentIndex(fileName)
+                    || CacheFileTree.isDefragmentLinkMapping(fileName)
             )
                 U.delete(file);
         }
@@ -109,28 +81,27 @@ public class DefragmentationFileUtils {
     /**
      * Checks whether cache group defragmentation completed or not. Completes 
it if all that's left is renaming.
      *
-     * @param workDir Cache group working directory.
-     * @param grpId Cache group Id of cache group belonging to the given 
working directory.
+     * @param cft Cache file tree.
      * @param log Logger to write messages.
      * @return {@code true} if given cache group is already defragmented.
      * @throws IgniteException If {@link IOException} occurred.
      *
-     * @see DefragmentationFileUtils#defragmentationCompletionMarkerFile(File)
+     * @see CacheFileTree#defragmentationCompletionMarkerFile()
      */
-    public static boolean skipAlreadyDefragmentedCacheGroup(File workDir, int 
grpId, IgniteLogger log) throws IgniteException {
-        File completionMarkerFile = 
defragmentationCompletionMarkerFile(workDir);
+    public static boolean skipAlreadyDefragmentedCacheGroup(CacheFileTree cft, 
IgniteLogger log) throws IgniteException {
+        File completionMarkerFile = cft.defragmentationCompletionMarkerFile();
 
         if (completionMarkerFile.exists()) {
             if (log.isInfoEnabled()) {
                 log.info(S.toString(
                     "Skipping already defragmented page group",
-                    "grpId", grpId, false,
+                    "grpId", cft.groupId(), false,
                     "markerFileName", completionMarkerFile.getName(), false,
-                    "workDir", workDir.getAbsolutePath(), false
+                    "workDir", cft.storage().getAbsolutePath(), false
                 ));
             }
 
-            batchRenameDefragmentedCacheGroupPartitions(workDir, log);
+            batchRenameDefragmentedCacheGroupPartitions(cft);
 
             return true;
         }
@@ -142,37 +113,36 @@ public class DefragmentationFileUtils {
      * Checks whether partition has already been defragmented or not. Cleans 
corrupted data if previous failed
      * defragmentation attempt was found.
      *
-     * @param workDir Cache group working directory.
-     * @param grpId Cache group Id of cache group belonging to the given 
working directory.
+     * @param cft Cache file tree.
      * @param partId Partition index to check.
      * @param log Logger to write messages.
      * @return {@code true} if given partition is already defragmented.
      * @throws IgniteException If {@link IOException} occurred.
      *
-     * @see DefragmentationFileUtils#defragmentedPartTmpFile(File, int)
-     * @see DefragmentationFileUtils#defragmentedPartFile(File, int)
-     * @see DefragmentationFileUtils#defragmentedPartMappingFile(File, int)
+     * @see CacheFileTree#defragmentedPartTmpFile(int)
+     * @see CacheFileTree#defragmentedPartFile(int)
+     * @see CacheFileTree#defragmentedPartMappingFile(int)
      */
-    public static boolean skipAlreadyDefragmentedPartition(File workDir, int 
grpId, int partId, IgniteLogger log) throws IgniteException {
-        File defragmentedPartFile = defragmentedPartFile(workDir, partId);
-        File defragmentedPartMappingFile = 
defragmentedPartMappingFile(workDir, partId);
+    public static boolean skipAlreadyDefragmentedPartition(CacheFileTree cft, 
int partId, IgniteLogger log) throws IgniteException {
+        File defragmentedPartFile = cft.defragmentedPartFile(partId);
+        File defragmentedPartMappingFile = 
cft.defragmentedPartMappingFile(partId);
 
         if (defragmentedPartFile.exists() && 
defragmentedPartMappingFile.exists()) {
             if (log.isInfoEnabled()) {
                 log.info(S.toString(
                     "Skipping already defragmented partition",
-                    "grpId", grpId, false,
+                    "grpId", cft.groupId(), false,
                     "partId", partId, false,
                     "partFileName", defragmentedPartFile.getName(), false,
                     "mappingFileName", defragmentedPartMappingFile.getName(), 
false,
-                    "workDir", workDir.getAbsolutePath(), false
+                    "workDir", cft.storage().getAbsolutePath(), false
                 ));
             }
 
             return true;
         }
 
-        File defragmentedPartTmpFile = defragmentedPartTmpFile(workDir, 
partId);
+        File defragmentedPartTmpFile = cft.defragmentedPartTmpFile(partId);
 
         try {
             Files.deleteIfExists(defragmentedPartTmpFile.toPath());
@@ -198,34 +168,33 @@ public class DefragmentationFileUtils {
      * Deletion of the marker must be done outside of defragmentation mode to 
prevent cache groups to be defragmentated
      * several times in case of failures.
      *
-     * @param workDir Cache group working directory.
-     * @param log Logger to write messages.
+     * @param cft Cache file tree.
      * @throws IgniteException If {@link IOException} occurred.
      *
-     * @see 
DefragmentationFileUtils#writeDefragmentationCompletionMarker(FileIOFactory, 
File, IgniteLogger)
+     * @see 
DefragmentationFileUtils#writeDefragmentationCompletionMarker(FileIOFactory, 
CacheFileTree, IgniteLogger)
      */
-    public static void batchRenameDefragmentedCacheGroupPartitions(File 
workDir, IgniteLogger log) throws IgniteException {
-        File completionMarkerFile = 
defragmentationCompletionMarkerFile(workDir);
+    public static void 
batchRenameDefragmentedCacheGroupPartitions(CacheFileTree cft) throws 
IgniteException {
+        File completionMarkerFile = cft.defragmentationCompletionMarkerFile();
 
         if (!completionMarkerFile.exists())
             return;
 
         try {
-            for (File mappingFile : workDir.listFiles((dir, name) -> 
name.startsWith(DFRG_LINK_MAPPING_FILE_PREFIX)))
+            for (File mappingFile : cft.storage().listFiles((dir, name) -> 
CacheFileTree.isDefragmentLinkMapping(name)))
                 Files.delete(mappingFile.toPath());
 
-            for (File partFile : workDir.listFiles((dir, name) -> 
name.startsWith(DFRG_PARTITION_FILE_PREFIX))) {
+            for (File partFile : cft.storage().listFiles((dir, name) -> 
CacheFileTree.isDefragmentPartition(name))) {
                 int partId = extractPartId(partFile.getName());
 
-                File oldPartFile = new File(workDir, 
partitionFileName(partId));
+                File oldPartFile = cft.partitionFile(partId);
 
                 Files.move(partFile.toPath(), oldPartFile.toPath(), 
ATOMIC_MOVE, REPLACE_EXISTING);
             }
 
-            File idxFile = new File(workDir, DFRG_INDEX_FILE_NAME);
+            File idxFile = cft.defragmentedIndexFile();
 
             if (idxFile.exists()) {
-                File oldIdxFile = new File(workDir, 
partitionFileName(INDEX_PARTITION));
+                File oldIdxFile = cft.partitionFile(INDEX_PARTITION);
 
                 Files.move(idxFile.toPath(), oldIdxFile.toPath(), ATOMIC_MOVE, 
REPLACE_EXISTING);
             }
@@ -235,64 +204,18 @@ public class DefragmentationFileUtils {
         }
     }
 
-    /**
-     * Extracts partition number from file names like {@code part-dfrg-%d.bin}.
-     *
-     * @param dfrgPartFileName Defragmented partition file name.
-     * @return Partition index.
-     *
-     * @see DefragmentationFileUtils#defragmentedPartFile(File, int)
-     */
-    private static int extractPartId(String dfrgPartFileName) {
-        assert dfrgPartFileName.startsWith(DFRG_PARTITION_FILE_PREFIX) : 
dfrgPartFileName;
-        assert dfrgPartFileName.endsWith(FILE_SUFFIX) : dfrgPartFileName;
-
-        String partIdStr = dfrgPartFileName.substring(
-            DFRG_PARTITION_FILE_PREFIX.length(),
-            dfrgPartFileName.length() - FILE_SUFFIX.length()
-        );
-
-        return Integer.parseInt(partIdStr);
-    }
-
-    /**
-     * Return file named {@code index-dfrg.bin.tmp} in given folder. It will 
be used for storing defragmented index
-     * partition during the process.
-     *
-     * @param workDir Cache group working directory.
-     * @return File.
-     *
-     * @see DefragmentationFileUtils#defragmentedIndexFile(File)
-     */
-    public static File defragmentedIndexTmpFile(File workDir) {
-        return new File(workDir, DFRG_INDEX_TMP_FILE_NAME);
-    }
-
-    /**
-     * Return file named {@code index-dfrg.bin} in given folder. It will be 
used for storing defragmented index
-     * partition when the process is over.
-     *
-     * @param workDir Cache group working directory.
-     * @return File.
-     *
-     * @see DefragmentationFileUtils#defragmentedIndexTmpFile(File)
-     */
-    public static File defragmentedIndexFile(File workDir) {
-        return new File(workDir, DFRG_INDEX_FILE_NAME);
-    }
-
     /**
      * Rename temporary index defragmentation file to a finalized one.
      *
-     * @param workDir Cache group working directory.
+     * @param cft Cache file tree.
      * @throws IgniteException If {@link IOException} occurred.
      *
-     * @see DefragmentationFileUtils#defragmentedIndexTmpFile(File)
-     * @see DefragmentationFileUtils#defragmentedIndexFile(File)
+     * @see CacheFileTree#defragmentedIndexTmpFile()
+     * @see CacheFileTree#defragmentedIndexFile()
      */
-    public static void renameTempIndexFile(File workDir) throws 
IgniteException {
-        File defragmentedIdxTmpFile = defragmentedIndexTmpFile(workDir);
-        File defragmentedIdxFile = defragmentedIndexFile(workDir);
+    public static void renameTempIndexFile(CacheFileTree cft) throws 
IgniteException {
+        File defragmentedIdxTmpFile = cft.defragmentedIndexTmpFile();
+        File defragmentedIdxFile = cft.defragmentedIndexFile();
 
         try {
             Files.deleteIfExists(defragmentedIdxFile.toPath());
@@ -304,47 +227,19 @@ public class DefragmentationFileUtils {
         }
     }
 
-    /**
-     * Return file named {@code part-dfrg-%d.bin.tmp} in given folder. It will 
be used for storing defragmented data
-     * partition during the process.
-     *
-     * @param workDir Cache group working directory.
-     * @param partId Partition index, will be substituted into file name.
-     * @return File.
-     *
-     * @see DefragmentationFileUtils#defragmentedPartFile(File, int)
-     */
-    public static File defragmentedPartTmpFile(File workDir, int partId) {
-        return new File(workDir, 
String.format(DFRG_PARTITION_TMP_FILE_TEMPLATE, partId));
-    }
-
-    /**
-     * Return file named {@code part-dfrg-%d.bin} in given folder. It will be 
used for storing defragmented data
-     * partition when the process is over.
-     *
-     * @param workDir Cache group working directory.
-     * @param partId Partition index, will be substituted into file name.
-     * @return File.
-     *
-     * @see DefragmentationFileUtils#defragmentedPartTmpFile(File, int)
-     */
-    public static File defragmentedPartFile(File workDir, int partId) {
-        return new File(workDir, String.format(DFRG_PARTITION_FILE_TEMPLATE, 
partId));
-    }
-
     /**
      * Rename temporary partition defragmentation file to a finalized one.
      *
-     * @param workDir Cache group working directory.
+     * @param cft Cache file tree.
      * @param partId Partition index.
      * @throws IgniteException If {@link IOException} occurred.
      *
-     * @see DefragmentationFileUtils#defragmentedPartTmpFile(File, int)
-     * @see DefragmentationFileUtils#defragmentedPartFile(File, int)
+     * @see CacheFileTree#defragmentedPartTmpFile(int)
+     * @see CacheFileTree#defragmentedPartFile(int)
      */
-    public static void renameTempPartitionFile(File workDir, int partId) 
throws IgniteException {
-        File defragmentedPartTmpFile = defragmentedPartTmpFile(workDir, 
partId);
-        File defragmentedPartFile = defragmentedPartFile(workDir, partId);
+    public static void renameTempPartitionFile(CacheFileTree cft, int partId) 
throws IgniteException {
+        File defragmentedPartTmpFile = cft.defragmentedPartTmpFile(partId);
+        File defragmentedPartFile = cft.defragmentedPartFile(partId);
 
         assert !defragmentedPartFile.exists() : defragmentedPartFile;
 
@@ -356,51 +251,22 @@ public class DefragmentationFileUtils {
         }
     }
 
-    /**
-     * Return file named {@code part-map-%d.bin} in given folder. It will be 
used for storing defragmention links
-     * mapping for given partition during and after defragmentation process. 
No temporary counterpart is required here.
-     *
-     * @param workDir Cache group working directory.
-     * @param partId Partition index, will be substituted into file name.
-     * @return File.
-     *
-     * @see LinkMap
-     */
-    public static File defragmentedPartMappingFile(File workDir, int partId) {
-        return new File(workDir, 
String.format(DFRG_LINK_MAPPING_FILE_TEMPLATE, partId));
-    }
-
-    /**
-     * Return defragmentation completion marker file. This file can only be 
created when all partitions and index are
-     * defragmented and renamed from their original {@code *.tmp} versions. 
Presence of this file signals that no data
-     * will be lost if original partitions are deleted and batch rename 
process can be safely initiated.
-     *
-     * @param workDir Cache group working directory.
-     * @return File.
-     *
-     * @see 
DefragmentationFileUtils#writeDefragmentationCompletionMarker(FileIOFactory, 
File, IgniteLogger)
-     * @see 
DefragmentationFileUtils#batchRenameDefragmentedCacheGroupPartitions(File, 
IgniteLogger)
-     */
-    public static File defragmentationCompletionMarkerFile(File workDir) {
-        return new File(workDir, DFRG_COMPLETION_MARKER_FILE_NAME);
-    }
-
     /**
      * Creates empty completion marker file in given directory.
      *
      * @param ioFactory File IO factory.
-     * @param workDir Cache group working directory.
+     * @param cft Cache file tree.
      * @param log Logger to write messages.
      * @throws IgniteException If {@link IOException} occurred.
      *
-     * @see DefragmentationFileUtils#defragmentationCompletionMarkerFile(File)
+     * @see CacheFileTree#defragmentationCompletionMarkerFile()
      */
     public static void writeDefragmentationCompletionMarker(
         FileIOFactory ioFactory,
-        File workDir,
+        CacheFileTree cft,
         IgniteLogger log
     ) throws IgniteException {
-        File completionMarker = defragmentationCompletionMarkerFile(workDir);
+        File completionMarker = cft.defragmentationCompletionMarkerFile();
 
         try (FileIO io = ioFactory.create(completionMarker, CREATE_NEW, 
WRITE)) {
             io.force(true);
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
index 0bcba962c0d..48e770b2dab 100755
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
@@ -39,7 +39,6 @@ import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.function.BiFunction;
 import java.util.function.Function;
-import java.util.function.IntFunction;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import org.apache.ignite.IgniteCheckedException;
@@ -64,6 +63,7 @@ import 
org.apache.ignite.internal.processors.cache.persistence.DataRegion;
 import 
org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import 
org.apache.ignite.internal.processors.cache.persistence.StorageException;
 import 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.FileTreeUtils;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree;
 import 
org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaStorage;
@@ -378,23 +378,14 @@ public class FilePageStoreManager extends 
GridCacheSharedManagerAdapter implemen
 
     /** {@inheritDoc} */
     @Override public void initializeForMetastorage() throws 
IgniteCheckedException {
-        int grpId = MetaStorage.METASTORAGE_CACHE_ID;
-
-        if (!idxCacheStores.containsKey(grpId)) {
-            DataRegion dataRegion = 
cctx.database().dataRegion(GridCacheDatabaseSharedManager.METASTORE_DATA_REGION_NAME);
-            PageMetrics pageMetrics = 
dataRegion.metrics().cacheGrpPageMetrics(grpId);
-
+        if (!idxCacheStores.containsKey(MetaStorage.METASTORAGE_CACHE_ID)) {
             CacheStoreHolder holder = initDir(
-                ft.metaStorage(),
-                p -> ft.metaStoragePartition(p).toPath(),
-                grpId,
-                MetaStorage.METASTORAGE_CACHE_NAME,
-                MetaStorage.METASTORAGE_PARTITIONS.size(),
-                pageMetrics,
-                false,
-                null);
+                ft.metastoreTree(),
+                null,
+                
cctx.database().dataRegion(GridCacheDatabaseSharedManager.METASTORE_DATA_REGION_NAME)
+            );
 
-            CacheStoreHolder old = idxCacheStores.put(grpId, holder);
+            CacheStoreHolder old = 
idxCacheStores.put(MetaStorage.METASTORAGE_CACHE_ID, holder);
 
             assert old == null : "Non-null old store holder for metastorage";
         }
@@ -476,19 +467,10 @@ public class FilePageStoreManager extends 
GridCacheSharedManagerAdapter implemen
     private CacheStoreHolder initForCache(CacheGroupDescriptor grpDesc, 
CacheConfiguration ccfg) throws IgniteCheckedException {
         assert !grpDesc.sharedGroup() || ccfg.getGroupName() != null : 
ccfg.getName();
 
-        String dataRegionName = grpDesc.config().getDataRegionName();
-        DataRegion dataRegion = cctx.database().dataRegion(dataRegionName);
-        PageMetrics pageMetrics = 
dataRegion.metrics().cacheGrpPageMetrics(grpDesc.groupId());
-
         return initDir(
-            ft.cacheStorage(ccfg),
-            p -> ft.partitionFile(ccfg, p).toPath(),
-            grpDesc.groupId(),
-            ccfg.getName(),
-            grpDesc.config().getAffinity().partitions(),
-            pageMetrics,
-            ccfg.isEncryptionEnabled(),
-            grpDesc.caches().keySet()
+            ft.cacheTree(ccfg),
+            grpDesc,
+            cctx.database().dataRegion(grpDesc.config().getDataRegionName())
         );
     }
 
@@ -555,59 +537,59 @@ public class FilePageStoreManager extends 
GridCacheSharedManagerAdapter implemen
     }
 
     /**
-     * @param cacheWorkDir Cache work dir.
-     * @param grpId Group ID.
-     * @param cacheName Cache name.
-     * @param partitions Number of partitions.
-     * @param pageMetrics Page metrics.
-     * @param encrypted {@code True} if this cache encrypted.
+     * @param cft Cache file tree.
+     * @param grpDesc Cache group description.
+     * @param dataRegion Data region.
      * @return Cache store holder.
      * @throws IgniteCheckedException If failed.
      */
     private CacheStoreHolder initDir(
-        File cacheWorkDir,
-        IntFunction<Path> partitionFile,
-        int grpId,
-        String cacheName,
-        int partitions,
-        PageMetrics pageMetrics,
-        boolean encrypted,
-        Collection<String> grpCaches) throws IgniteCheckedException {
+        CacheFileTree cft,
+        @Nullable CacheGroupDescriptor grpDesc,
+        DataRegion dataRegion
+    ) throws IgniteCheckedException {
         try {
-            boolean dirExisted = checkAndInitCacheWorkDir(cacheWorkDir, log);
+            boolean dirExisted = checkAndInitCacheWorkDir(cft);
 
             if (dirExisted) {
                 MaintenanceRegistry mntcReg = 
cctx.kernalContext().maintenanceRegistry();
 
                 if (!mntcReg.isMaintenanceMode())
-                    
DefragmentationFileUtils.beforeInitPageStores(cacheWorkDir, log);
+                    DefragmentationFileUtils.beforeInitPageStores(cft);
             }
 
-            File idxFile = partitionFile.apply(INDEX_PARTITION).toFile();
+            File idxFile = cft.partitionFile(INDEX_PARTITION);
 
             GridQueryProcessor qryProc = cctx.kernalContext().query();
 
             if (qryProc.moduleEnabled()) {
-                boolean idxRecreating = grpCaches == null
+                String cacheName = cft.name();
+
+                boolean idxRecreating = cft.metastore()
                     ? !qryProc.recreateCompleted(cacheName)
-                    : grpCaches.stream().anyMatch(name -> 
!qryProc.recreateCompleted(name));
+                    : grpDesc.caches().keySet().stream().anyMatch(name -> 
!qryProc.recreateCompleted(name));
 
                 if (idxFile.exists() && idxRecreating) {
                     log.warning("Recreate of index.bin don't finish before 
node stop, index.bin can be inconsistent. " +
-                        "Removing it to recreate one more time [grpId=" + 
grpId + ", cacheName=" + cacheName + ']');
+                        "Removing it to recreate one more time [grpId=" + 
cft.groupId() + ", cacheName=" + cacheName + ']');
 
                     if (!idxFile.delete()) {
                         throw new IgniteCheckedException(
-                            "Failed to remove index.bin [grpId=" + grpId + ", 
cacheName=" + cacheName + ']'
+                            "Failed to remove index.bin [grpId=" + 
cft.groupId() + ", cacheName=" + cacheName + ']'
                         );
                     }
                 }
             }
 
             if (dirExisted && !idxFile.exists())
-                grpsWithoutIdx.add(grpId);
+                grpsWithoutIdx.add(cft.groupId());
 
-            FileVersionCheckingFactory pageStoreFactory = 
getPageStoreFactory(grpId, encrypted);
+            FileVersionCheckingFactory pageStoreFactory = getPageStoreFactory(
+                cft.groupId(),
+                !cft.metastore() && cft.config().isEncryptionEnabled()
+            );
+
+            PageMetrics pageMetrics = 
dataRegion.metrics().cacheGrpPageMetrics(cft.groupId());
 
             PageStore idxStore =
                 pageStoreFactory.createPageStore(
@@ -615,7 +597,9 @@ public class FilePageStoreManager extends 
GridCacheSharedManagerAdapter implemen
                     idxFile,
                     pageMetrics.totalPages()::add);
 
-            PageStore[] partStores = new PageStore[partitions];
+            PageStore[] partStores = new PageStore[cft.metastore()
+                ? MetaStorage.METASTORAGE_PARTITIONS.size()
+                : grpDesc.config().getAffinity().partitions()];
 
             for (int partId = 0; partId < partStores.length; partId++) {
                 final int p = partId;
@@ -623,7 +607,7 @@ public class FilePageStoreManager extends 
GridCacheSharedManagerAdapter implemen
                 PageStore partStore =
                     pageStoreFactory.createPageStore(
                         PageStore.TYPE_DATA,
-                        () -> partitionFile.apply(p),
+                        () -> cft.partitionFile(p).toPath(),
                         pageMetrics.totalPages()::add);
 
                 partStores[partId] = partStore;
@@ -640,9 +624,11 @@ public class FilePageStoreManager extends 
GridCacheSharedManagerAdapter implemen
     }
 
     /**
-     * @param cacheWorkDir Cache work directory.
+     * @param cft Cache file tree.
      */
-    public static boolean checkAndInitCacheWorkDir(File cacheWorkDir, 
IgniteLogger log) throws IgniteCheckedException {
+    public static boolean checkAndInitCacheWorkDir(CacheFileTree cft) throws 
IgniteCheckedException {
+        File cacheWorkDir = cft.storage();
+
         boolean dirExisted = false;
 
         ReadWriteLock lock = 
initDirLock.getLock(cacheWorkDir.getName().hashCode());
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/CacheFileTree.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/CacheFileTree.java
new file mode 100644
index 00000000000..498564bcf2a
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/CacheFileTree.java
@@ -0,0 +1,258 @@
+/*
+ * 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.ignite.internal.processors.cache.persistence.filename;
+
+import java.io.File;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.configuration.CacheConfiguration;
+import 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils;
+import 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.LinkMap;
+import 
org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory;
+import 
org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaStorage;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.jetbrains.annotations.Nullable;
+
+import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.FILE_SUFFIX;
+import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.INDEX_FILE_PREFIX;
+import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.PART_FILE_PREFIX;
+import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.TMP_SUFFIX;
+
+/**
+ * Class to be used in common code: for metastorage or regular cache.
+ */
+public class CacheFileTree {
+    /** Prefix for link mapping files. */
+    private static final String DFRG_LINK_MAPPING_FILE_PREFIX = 
PART_FILE_PREFIX + "map-";
+
+    /** Link mapping file template. */
+    private static final String DFRG_LINK_MAPPING_FILE_TEMPLATE = 
DFRG_LINK_MAPPING_FILE_PREFIX + "%d" + FILE_SUFFIX;
+
+    /** Defragmentation complation marker file name. */
+    private static final String DFRG_COMPLETION_MARKER_FILE_NAME = 
"dfrg-completion-marker";
+
+    /** Name of defragmentated index partition file. */
+    private static final String DFRG_INDEX_FILE_NAME = INDEX_FILE_PREFIX + 
"-dfrg" + FILE_SUFFIX;
+
+    /** Name of defragmentated index partition temporary file. */
+    private static final String DFRG_INDEX_TMP_FILE_NAME = 
DFRG_INDEX_FILE_NAME + TMP_SUFFIX;
+
+    /** Prefix for defragmented partition files. */
+    private static final String DFRG_PARTITION_FILE_PREFIX = PART_FILE_PREFIX 
+ "dfrg-";
+
+    /** Defragmented partition file template. */
+    private static final String DFRG_PARTITION_FILE_TEMPLATE = 
DFRG_PARTITION_FILE_PREFIX + "%d" + FILE_SUFFIX;
+
+    /** Defragmented partition temp file template. */
+    private static final String DFRG_PARTITION_TMP_FILE_TEMPLATE = 
DFRG_PARTITION_FILE_TEMPLATE + TMP_SUFFIX;
+
+    /** Node file tree. */
+    private final NodeFileTree ft;
+
+    /** Cache storage. */
+    private final File storage;
+
+    /** {@code True} if tree for metastore, {@code false} otherwise. */
+    private final boolean metastore;
+
+    /** Cache configuration. {@code Null} only if {@code metastore == true}. */
+    private final @Nullable CacheConfiguration<?, ?> ccfg;
+
+    /** Cache configuration. {@code Null} only if {@code metastore == true}. */
+    private final int grpId;
+
+    /**
+     * @param ft Node file tree.
+     * @param metastore {@code True} if tree for metastore, {@code false} 
otherwise.
+     * @param ccfg Cache configuration. {@code Null} only if {@code metastore 
== true}.
+     */
+    CacheFileTree(NodeFileTree ft, boolean metastore, @Nullable 
CacheConfiguration<?, ?> ccfg) {
+        assert ccfg != null || metastore;
+
+        this.ft = ft;
+        this.metastore = metastore;
+        this.storage = metastore ? ft.metaStorage() : ft.cacheStorage(ccfg);
+        this.ccfg = ccfg;
+        this.grpId = metastore ? MetaStorage.METASTORAGE_CACHE_ID : 
CU.cacheGroupId(ccfg);
+    }
+
+    /**
+     * @return Storage for cache.
+     */
+    public File storage() {
+        return storage;
+    }
+
+    /**
+     * @return Cache configuration.
+     */
+    @Nullable public CacheConfiguration<?, ?> config() {
+        return ccfg;
+    }
+
+    /**
+     * @return {@code True} if tree for metastore, {@code false} otherwise.
+     */
+    public boolean metastore() {
+        return metastore;
+    }
+
+    /**
+     * @param part Partition id.
+     * @return Partition file.
+     */
+    public File partitionFile(int part) {
+        return metastore
+            ? ft.metaStoragePartition(part)
+            : ft.partitionFile(ccfg, part);
+    }
+
+    /**
+     * @return Cache name.
+     */
+    public String name() {
+        return metastore ? MetaStorage.METASTORAGE_CACHE_NAME : ccfg.getName();
+    }
+
+    /**
+     * @return Gropu id.
+     */
+    public int groupId() {
+        return grpId;
+    }
+
+    /**
+     * Return file named {@code index-dfrg.bin.tmp} in given folder. It will 
be used for storing defragmented index
+     * partition during the process.
+     *
+     * @return File.
+     *
+     * @see CacheFileTree#defragmentedIndexFile()
+     */
+    public File defragmentedIndexTmpFile() {
+        return new File(storage(), DFRG_INDEX_TMP_FILE_NAME);
+    }
+
+    /**
+     * Return file named {@code index-dfrg.bin} in given folder. It will be 
used for storing defragmented index
+     * partition when the process is over.
+     *
+     * @return File.
+     *
+     * @see #defragmentedIndexTmpFile()
+     */
+    public File defragmentedIndexFile() {
+        return new File(storage(), DFRG_INDEX_FILE_NAME);
+    }
+
+    /**
+     * Return file named {@code part-dfrg-%d.bin.tmp} in given folder. It will 
be used for storing defragmented data
+     * partition during the process.
+     *
+     * @param partId Partition index, will be substituted into file name.
+     * @return File.
+     *
+     * @see #defragmentedPartFile(int)
+     */
+    public File defragmentedPartTmpFile(int partId) {
+        return new File(storage(), 
String.format(DFRG_PARTITION_TMP_FILE_TEMPLATE, partId));
+    }
+
+    /**
+     * Return file named {@code part-dfrg-%d.bin} in given folder. It will be 
used for storing defragmented data
+     * partition when the process is over.
+     *
+     * @param partId Partition index, will be substituted into file name.
+     * @return File.
+     *
+     * @see #defragmentedPartTmpFile(int)
+     */
+    public File defragmentedPartFile(int partId) {
+        return new File(storage(), String.format(DFRG_PARTITION_FILE_TEMPLATE, 
partId));
+    }
+
+    /**
+     * Return file named {@code part-map-%d.bin} in given folder. It will be 
used for storing defragmention links
+     * mapping for given partition during and after defragmentation process. 
No temporary counterpart is required here.
+     *
+     * @param partId Partition index, will be substituted into file name.
+     * @return File.
+     *
+     * @see LinkMap
+     */
+    public File defragmentedPartMappingFile(int partId) {
+        return new File(storage(), 
String.format(DFRG_LINK_MAPPING_FILE_TEMPLATE, partId));
+    }
+
+    /**
+     * Return defragmentation completion marker file. This file can only be 
created when all partitions and index are
+     * defragmented and renamed from their original {@code *.tmp} versions. 
Presence of this file signals that no data
+     * will be lost if original partitions are deleted and batch rename 
process can be safely initiated.
+     *
+     * @return File.
+     *
+     * @see 
DefragmentationFileUtils#writeDefragmentationCompletionMarker(FileIOFactory, 
CacheFileTree, IgniteLogger)
+     * @see 
DefragmentationFileUtils#batchRenameDefragmentedCacheGroupPartitions(CacheFileTree)
+     */
+    public File defragmentationCompletionMarkerFile() {
+        return new File(storage(), DFRG_COMPLETION_MARKER_FILE_NAME);
+    }
+
+    /**
+     * @param fileName File name.
+     * @return {@code True} if name is defragment partition file.
+     */
+    public static boolean isDefragmentPartition(String fileName) {
+        return fileName.startsWith(DFRG_PARTITION_FILE_PREFIX);
+    }
+
+    /**
+     * @param fileName File name.
+     * @return {@code True} if name is defragment index file.
+     */
+    public static boolean isDefragmentIndex(String fileName) {
+        return fileName.startsWith(DFRG_INDEX_FILE_NAME);
+    }
+
+    /**
+     * @param fileName File name.
+     * @return {@code True} if name is defragment link mapping file.
+     */
+    public static boolean isDefragmentLinkMapping(String fileName) {
+        return fileName.startsWith(DFRG_LINK_MAPPING_FILE_PREFIX);
+    }
+
+    /**
+     * Extracts partition number from file names like {@code part-dfrg-%d.bin}.
+     *
+     * @param dfrgPartFileName Defragmented partition file name.
+     * @return Partition index.
+     *
+     * @see #defragmentedPartFile(int)
+     */
+    public static int extractPartId(String dfrgPartFileName) {
+        assert dfrgPartFileName.startsWith(DFRG_PARTITION_FILE_PREFIX) : 
dfrgPartFileName;
+        assert dfrgPartFileName.endsWith(FILE_SUFFIX) : dfrgPartFileName;
+
+        String partIdStr = dfrgPartFileName.substring(
+            DFRG_PARTITION_FILE_PREFIX.length(),
+            dfrgPartFileName.length() - FILE_SUFFIX.length()
+        );
+
+        return Integer.parseInt(partIdStr);
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/NodeFileTree.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/NodeFileTree.java
index 76db1b05f0b..f8af446426b 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/NodeFileTree.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/filename/NodeFileTree.java
@@ -205,10 +205,10 @@ public class NodeFileTree extends SharedFileTree {
             dir.getName().equals(METASTORAGE_DIR_NAME);
 
     /** Partition file prefix. */
-    public static final String PART_FILE_PREFIX = "part-";
+    static final String PART_FILE_PREFIX = "part-";
 
     /** Index file prefix. */
-    public static final String INDEX_FILE_PREFIX = "index";
+    static final String INDEX_FILE_PREFIX = "index";
 
     /** Index file name. */
     protected static final String INDEX_FILE_NAME = INDEX_FILE_PREFIX + 
FILE_SUFFIX;
@@ -802,6 +802,21 @@ public class NodeFileTree extends SharedFileTree {
         return Long.parseLong(fn.substring(0, fn.indexOf('.')));
     }
 
+    /**
+     * @return Tree for metastorage cache.
+     */
+    public CacheFileTree metastoreTree() {
+        return new CacheFileTree(this, true, null);
+    }
+
+    /**
+     * @param ccfg Cache configuration.
+     * @return Tree for cache.
+     */
+    public CacheFileTree cacheTree(CacheConfiguration<?, ?> ccfg) {
+        return new CacheFileTree(this, false, ccfg);
+    }
+
     /**
      * @param includeMeta If {@code true} then include metadata directory into 
results.
      * @param filter Cache group names to filter.
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDefragmentationTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDefragmentationTest.java
index c224dcbcee2..a20dfd61fc1 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDefragmentationTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDefragmentationTest.java
@@ -58,9 +58,9 @@ import 
org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.maintenance.MaintenanceFileStore;
 import org.apache.ignite.internal.pagemem.store.PageStoreCollection;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
-import 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FilePageStore;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree;
 import 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree;
 import org.apache.ignite.internal.util.lang.IgniteThrowableConsumer;
 import org.apache.ignite.maintenance.MaintenanceRegistry;
@@ -70,10 +70,6 @@ import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static 
org.apache.ignite.internal.pagemem.PageIdAllocator.INDEX_PARTITION;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentationCompletionMarkerFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedIndexFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedPartFile;
-import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils.defragmentedPartMappingFile;
 import static 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.maintenance.DefragmentationParameters.toStore;
 
 /** */
@@ -233,7 +229,7 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
 
         stopGrid(0);
 
-        File workDir = ft.cacheStorage(ccfg);
+        CacheFileTree cft = ft.cacheTree(ccfg);
 
         long[] oldPartLen = partitionSizes(ft, ccfg);
 
@@ -265,7 +261,7 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
 
         assertTrue(newIdxFileLen <= oldIdxFileLen);
 
-        File completionMarkerFile = 
defragmentationCompletionMarkerFile(workDir);
+        File completionMarkerFile = cft.defragmentationCompletionMarkerFile();
         assertTrue(completionMarkerFile.exists());
 
         stopGrid(0);
@@ -278,7 +274,7 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
 
         validateCache(grid(0).cache(DEFAULT_CACHE_NAME));
 
-        validateLeftovers(workDir);
+        validateLeftovers(cft);
     }
 
     /** */
@@ -362,9 +358,9 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testFailoverRestartWithoutDefragmentation() throws Exception {
-        testFailover(workDir -> {
+        testFailover(cft -> {
             try {
-                File mntcRecFile = new File(workDir.getParent(), 
MaintenanceFileStore.MAINTENANCE_FILE_NAME);
+                File mntcRecFile = new File(cft.storage().getParent(), 
MaintenanceFileStore.MAINTENANCE_FILE_NAME);
 
                 assertTrue(mntcRecFile.exists());
 
@@ -372,7 +368,7 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
 
                 startGrid(0);
 
-                validateLeftovers(workDir);
+                validateLeftovers(cft);
             }
             catch (Exception e) {
                 throw new IgniteCheckedException(e);
@@ -392,7 +388,7 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testFailoverOnLastStage() throws Exception {
-        testFailover(workDir -> {});
+        testFailover(cft -> {});
     }
 
     /**
@@ -402,9 +398,9 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testFailoverIncompletedIndex() throws Exception {
-        testFailover(workDir -> move(
-            DefragmentationFileUtils.defragmentedIndexFile(workDir),
-            DefragmentationFileUtils.defragmentedIndexTmpFile(workDir)
+        testFailover(cft -> move(
+            cft.defragmentedIndexFile(),
+            cft.defragmentedIndexTmpFile()
         ));
     }
 
@@ -415,12 +411,12 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testFailoverIncompletedPartition1() throws Exception {
-        testFailover(workDir -> {
-            DefragmentationFileUtils.defragmentedIndexFile(workDir).delete();
+        testFailover(cft -> {
+            cft.defragmentedIndexFile().delete();
 
             move(
-                DefragmentationFileUtils.defragmentedPartFile(workDir, PARTS - 
1),
-                DefragmentationFileUtils.defragmentedPartTmpFile(workDir, 
PARTS - 1)
+                cft.defragmentedPartFile(PARTS - 1),
+                cft.defragmentedPartTmpFile(PARTS - 1)
             );
         });
     }
@@ -432,10 +428,10 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testFailoverIncompletedPartition2() throws Exception {
-        testFailover(workDir -> {
-            DefragmentationFileUtils.defragmentedIndexFile(workDir).delete();
+        testFailover(cft -> {
+            cft.defragmentedIndexFile().delete();
 
-            DefragmentationFileUtils.defragmentedPartMappingFile(workDir, 
PARTS - 1).delete();
+            cft.defragmentedPartMappingFile(PARTS - 1).delete();
         });
     }
 
@@ -450,7 +446,7 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
     }
 
     /** */
-    private void testFailover(IgniteThrowableConsumer<File> c) throws 
Exception {
+    private void testFailover(IgniteThrowableConsumer<CacheFileTree> c) throws 
Exception {
         IgniteEx ig = startGrid(0);
 
         ig.cluster().state(ClusterState.ACTIVE);
@@ -461,14 +457,14 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
 
         createMaintenanceRecord();
 
-        File workDir = 
ig.context().pdsFolderResolver().fileTree().cacheStorage(ig.cachex(DEFAULT_CACHE_NAME).configuration());
+        CacheFileTree cft = 
ig.context().pdsFolderResolver().fileTree().cacheTree(ig.cachex(DEFAULT_CACHE_NAME).configuration());
 
         stopGrid(0);
 
         //Defragmentation should fail when node starts.
-        startAndAwaitNodeFail(workDir);
+        startAndAwaitNodeFail(cft);
 
-        c.accept(workDir);
+        c.accept(cft);
 
         startGrid(0); // Fails here VERY rarely. WTF?
 
@@ -481,13 +477,13 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
 
         validateCache(grid(0).cache(DEFAULT_CACHE_NAME));
 
-        validateLeftovers(workDir);
+        validateLeftovers(cft);
     }
 
     /**
      * @throws IgniteInterruptedCheckedException If fail.
      */
-    private void startAndAwaitNodeFail(File workDir) throws 
IgniteInterruptedCheckedException {
+    private void startAndAwaitNodeFail(CacheFileTree cft) throws 
IgniteInterruptedCheckedException {
         String errMsg = "Failed to create defragmentation completion marker.";
 
         AtomicBoolean errOccurred = new AtomicBoolean();
@@ -496,9 +492,10 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
             DataStorageConfiguration dsCfg = cfg.getDataStorageConfiguration();
 
             FileIOFactory delegate = dsCfg.getFileIOFactory();
+            File marker = cft.defragmentationCompletionMarkerFile();
 
             dsCfg.setFileIOFactory((file, modes) -> {
-                if (file.equals(defragmentationCompletionMarkerFile(workDir))) 
{
+                if (file.equals(marker)) {
                     errOccurred.set(true);
 
                     throw new IOException(errMsg);
@@ -539,13 +536,13 @@ public class IgnitePdsDefragmentationTest extends 
GridCommonAbstractTest {
     }
 
     /** */
-    public void validateLeftovers(File workDir) {
-        assertFalse(defragmentedIndexFile(workDir).exists());
+    public void validateLeftovers(CacheFileTree cft) {
+        assertFalse(cft.defragmentedIndexFile().exists());
 
         for (int p = 0; p < PARTS; p++) {
-            assertFalse(defragmentedPartMappingFile(workDir, p).exists());
+            assertFalse(cft.defragmentedPartMappingFile(p).exists());
 
-            assertFalse(defragmentedPartFile(workDir, p).exists());
+            assertFalse(cft.defragmentedPartFile(p).exists());
         }
     }
 
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCheckpointRecoveryTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCheckpointRecoveryTest.java
index a5af9249f3d..afe8d8dfa96 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCheckpointRecoveryTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCheckpointRecoveryTest.java
@@ -46,6 +46,7 @@ import 
org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FileIODecorator;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory;
 import 
org.apache.ignite.internal.processors.cache.persistence.file.RandomAccessFileIOFactory;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.FileTreeTestUtils;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
 import org.apache.ignite.testframework.GridTestUtils;
@@ -57,7 +58,6 @@ import org.junit.runners.Parameterized;
 
 import static 
org.apache.ignite.configuration.DataStorageConfiguration.DFLT_CP_RECOVERY_DATA_COMRESSION;
 import static 
org.apache.ignite.internal.processors.cache.persistence.checkpoint.CheckpointRecoveryFileStorage.FILE_NAME_PATTERN;
-import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.PART_FILE_PREFIX;
 
 /**
  * Class containing tests for applying checkpoint recovery data.
@@ -130,7 +130,7 @@ public class IgnitePdsCheckpointRecoveryTest extends 
GridCommonAbstractTest {
     /** */
     @Test
     public void testRecoverFromCheckpointRecoveryFiles() throws Exception {
-        spoilFilePattern = Pattern.compile('^' + 
Pattern.quote(PART_FILE_PREFIX) + ".*");
+        spoilFilePattern = FileTreeTestUtils.partitionFilePattern();
 
         IgniteEx ignite = initIgnite();
         IgniteCache<Integer, Integer> cache = ignite.cache(DEFAULT_CACHE_NAME);
@@ -189,7 +189,7 @@ public class IgnitePdsCheckpointRecoveryTest extends 
GridCommonAbstractTest {
     /** */
     @Test
     public void testFailToRecoverFromSpoiledCheckpointRecoveryFiles() throws 
Exception {
-        spoilFilePattern = Pattern.compile('^' + 
Pattern.quote(PART_FILE_PREFIX) + ".*");
+        spoilFilePattern = FileTreeTestUtils.partitionFilePattern();
 
         IgniteEx ignite = initIgnite();
 
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/filename/FileTreeTestUtils.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/filename/FileTreeTestUtils.java
new file mode 100644
index 00000000000..34dbff226f1
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/filename/FileTreeTestUtils.java
@@ -0,0 +1,32 @@
+/*
+ * 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.ignite.internal.processors.cache.persistence.filename;
+
+import java.util.regex.Pattern;
+
+import static 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree.PART_FILE_PREFIX;
+
+/** */
+public class FileTreeTestUtils {
+    /**
+     * @return Pattern to find partition files.
+     */
+    public static Pattern partitionFilePattern() {
+        return Pattern.compile('^' + Pattern.quote(PART_FILE_PREFIX) + ".*");
+    }
+}
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsIndexingDefragmentationTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsIndexingDefragmentationTest.java
index 372b6f0ad3a..9a25794a2de 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsIndexingDefragmentationTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsIndexingDefragmentationTest.java
@@ -39,8 +39,7 @@ import 
org.apache.ignite.internal.managers.indexing.IndexesRebuildTask;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import 
org.apache.ignite.internal.processors.cache.IgniteCacheUpdateSqlQuerySelfTest;
-import 
org.apache.ignite.internal.processors.cache.persistence.defragmentation.DefragmentationFileUtils;
-import 
org.apache.ignite.internal.processors.cache.persistence.filename.NodeFileTree;
+import 
org.apache.ignite.internal.processors.cache.persistence.filename.CacheFileTree;
 import 
org.apache.ignite.internal.processors.query.schema.IndexRebuildCancelToken;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.jetbrains.annotations.Nullable;
@@ -116,8 +115,8 @@ public class IgnitePdsIndexingDefragmentationTest extends 
IgnitePdsDefragmentati
 
         ig.cluster().state(ClusterState.ACTIVE);
 
-        NodeFileTree ft = ig.context().pdsFolderResolver().fileTree();
         CacheConfiguration<?, ?> dfltCacheCfg = 
ig.cachex(DEFAULT_CACHE_NAME).configuration();
+        CacheFileTree cft = 
ig.context().pdsFolderResolver().fileTree().cacheTree(dfltCacheCfg);
 
         fillCache(keyMapper, ig.cache(DEFAULT_CACHE_NAME));
 
@@ -127,20 +126,20 @@ public class IgnitePdsIndexingDefragmentationTest extends 
IgnitePdsDefragmentati
 
         stopGrid(0);
 
-        long oldIdxFileLen = ft.partitionFile(dfltCacheCfg, 
INDEX_PARTITION).length();
+        long oldIdxFileLen = cft.partitionFile(INDEX_PARTITION).length();
 
         startGrid(0);
 
         waitForDefragmentation(0);
 
-        long newIdxFileLen = ft.partitionFile(dfltCacheCfg, 
INDEX_PARTITION).length();
+        long newIdxFileLen = cft.partitionFile(INDEX_PARTITION).length();
 
         assertTrue(
             "newIdxFileLen=" + newIdxFileLen + ", oldIdxFileLen=" + 
oldIdxFileLen,
             newIdxFileLen <= oldIdxFileLen
         );
 
-        File completionMarkerFile = 
DefragmentationFileUtils.defragmentationCompletionMarkerFile(ft.cacheStorage(dfltCacheCfg));
+        File completionMarkerFile = cft.defragmentationCompletionMarkerFile();
 
         assertTrue("Completion marker file must exists", 
completionMarkerFile.exists());
 

Reply via email to